Add files copied from ATBQT application
This commit is contained in:
parent
c4d09eb2ea
commit
0ebe274e9a
750
apism/apism_client.cpp
Normal file
750
apism/apism_client.cpp
Normal file
@ -0,0 +1,750 @@
|
|||||||
|
#include "apism_client.h"
|
||||||
|
//#include "support/VendingData.h"
|
||||||
|
//#include "support/PersistentData.h"
|
||||||
|
//#include "support/utils.h"
|
||||||
|
//#include "ATBHMIconfig.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
#include <QListIterator>
|
||||||
|
#include <QScopedPointer>
|
||||||
|
#include <QUuid>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
// Q_DECLARE_METATYPE(QAbstractSocket::SocketError)
|
||||||
|
|
||||||
|
ApismClient::ApismClient(QObject *eventReceiver, ATBHMIconfig *config, PersistentData *persistentData, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, healthEventReceiver(eventReceiver)
|
||||||
|
, m_config(config)
|
||||||
|
, persistentData(persistentData)
|
||||||
|
, lastError(0)
|
||||||
|
, lastErrorDescription("")
|
||||||
|
, currentRequestUid("")
|
||||||
|
, currentRequest(ISMAS::REQUEST::NO_REQUEST)
|
||||||
|
{
|
||||||
|
this->apismTcpSendClient = new ApismTcpClient("127.0.0.1", "7777", this);
|
||||||
|
this->apismTcpRequestResponseClient = new ApismTcpClient("127.0.0.1", "7778", this);
|
||||||
|
|
||||||
|
connect(apismTcpRequestResponseClient, &ApismTcpClient::receivedData,
|
||||||
|
this, &ApismClient::onReceivedResponse);
|
||||||
|
connect(apismTcpRequestResponseClient, &ApismTcpClient::responseTimeout,
|
||||||
|
this, &ApismClient::onRequestResponseClientResponseTimeout);
|
||||||
|
|
||||||
|
connect(apismTcpSendClient, &ApismTcpClient::responseTimeout,
|
||||||
|
this, &ApismClient::onSendClientResponseTimeout);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// not needed as APISM closes the socket after we send data, so readyRead()
|
||||||
|
// might not even fire
|
||||||
|
// connect(&m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
|
||||||
|
|
||||||
|
// defined for Qt >= 5.15, we have 5.12
|
||||||
|
// qRegisterMetaType<QAbstractSocket::SocketError>();
|
||||||
|
// connect(&m_socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
|
||||||
|
// this, SLOT(onSocketError(&QAbstractSocket::SocketError)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ApismClient::~ApismClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ApismClient::restartApism()
|
||||||
|
{
|
||||||
|
QProcess::startDetached("/bin/systemctl", {"restart", "apism"});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//void ApismClient::onReadyRead() { // parse APISM response
|
||||||
|
// QByteArray data = m_socket.readAll();
|
||||||
|
// qCritical() << "APISM-RESPONSE = (" << endl << data << endl << ")";
|
||||||
|
//}
|
||||||
|
|
||||||
|
void ApismClient::sendTransaction(const VendingData *vendingData) {
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
QScopedPointer<ISMAS::TransferData> transferData(new ISMAS::TransferData());
|
||||||
|
|
||||||
|
PAYMENT_VARIANTS::TYPE paymentType = vendingData->getParameter("PaymentType").value<PAYMENT_VARIANTS::TYPE>();
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////// DEVICE //////////////////////////////////
|
||||||
|
bool deviceSet = false;
|
||||||
|
//QJsonValue tariffId("TariffInfo");
|
||||||
|
//transferData->device.insert("TARIFID", tariffId);
|
||||||
|
//QJsonValue group("group");
|
||||||
|
//transferData->device.insert("GROUP", group);
|
||||||
|
//QJsonValue zone("zone");
|
||||||
|
//transferData->device.insert("ZONE", zone);
|
||||||
|
if (deviceSet) {
|
||||||
|
transferData->insert("DEVICE", transferData->device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////// TRANSACTION /////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
bool transactionSet = false;
|
||||||
|
|
||||||
|
if (vendingData->hasParameter("TRANSACTION_STATE")) {
|
||||||
|
QVariant tstate = vendingData->getParameter("TRANSACTION_STATE");
|
||||||
|
if (tstate.isValid() && tstate.type() == QVariant::Int) {
|
||||||
|
transferData->transaction.state = tstate.toInt();
|
||||||
|
transferData->transaction.insert("STATE", transferData->transaction.state);
|
||||||
|
transactionSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("TRANSACTION_UID")) {
|
||||||
|
QVariant tuid = vendingData->getParameter("TRANSACTION_UID");
|
||||||
|
if (tuid.isValid() && tuid.type() == QVariant::String) {
|
||||||
|
transferData->transaction.uid = tuid.toString();
|
||||||
|
transferData->transaction.insert("UID", transferData->transaction.uid);
|
||||||
|
this->persistentData->setLastTransactionUID(tuid.toString());
|
||||||
|
transactionSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("TRANSACTION_TIMESTAMP")) {
|
||||||
|
QVariant tstamp = vendingData->getParameter("TRANSACTION_TIMESTAMP");
|
||||||
|
if (tstamp.isValid() && tstamp.type() == QVariant::String) {
|
||||||
|
transferData->transaction.timestamp = tstamp.toString();
|
||||||
|
transferData->transaction.insert("TIMESTAMP", transferData->transaction.timestamp);
|
||||||
|
transactionSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("TRANSACTION_TICKET_SEQUENCE_NUMBER")) {
|
||||||
|
QVariant tsn = vendingData->getParameter("TRANSACTION_TICKET_SEQUENCE_NUMBER");
|
||||||
|
if (tsn.isValid() && tsn.type() == QVariant::Int) {
|
||||||
|
transferData->transaction.seq_tick_number = tsn.toInt();
|
||||||
|
transferData->transaction.insert("TICKETNU", transferData->transaction.seq_tick_number);
|
||||||
|
transactionSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("LICENSEPLATE")) {
|
||||||
|
QVariant lp = vendingData->getParameter("LICENSEPLATE");
|
||||||
|
transferData->transaction.userText = QJsonValue::fromVariant(lp);
|
||||||
|
transferData->transaction.insert("USERTEXT", transferData->transaction.userText);
|
||||||
|
transferData->transaction.userTextType = "license plate";
|
||||||
|
transferData->transaction.insert("USERTEXTTYPE", transferData->transaction.userTextType);
|
||||||
|
transactionSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionSet) {
|
||||||
|
transferData->insert("TRANSACTION", transferData->transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////// ITEM //////////////////////////////////
|
||||||
|
bool itemSet = false;
|
||||||
|
|
||||||
|
if (vendingData->hasParameter("PermitType")) {
|
||||||
|
QVariant idVariant = vendingData->getParameter("PermitType");
|
||||||
|
transferData->item.id = idVariant.toString();
|
||||||
|
transferData->item.insert("ID", transferData->item.id);
|
||||||
|
itemSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("Product")) {
|
||||||
|
QVariant nameVariant = vendingData->getParameter("Product");
|
||||||
|
transferData->item.name = nameVariant.toString();
|
||||||
|
transferData->item.insert("NAME", transferData->item.name);
|
||||||
|
itemSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("PRICE_INFO_GROSS")) {
|
||||||
|
int priceUint = vendingData->getUintParameter("PRICE_INFO_GROSS");
|
||||||
|
transferData->item.price = priceUint;
|
||||||
|
transferData->item.insert("PRICE", transferData->item.price);
|
||||||
|
itemSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("PERIOD_START")) {
|
||||||
|
QVariant startTimeVariant = vendingData->getParameter("PERIOD_START");
|
||||||
|
transferData->item.startTime = utils::getISODateTimeWithMsAndOffset(startTimeVariant);
|
||||||
|
transferData->item.insert("STARTTIME", transferData->item.startTime);
|
||||||
|
itemSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("PERIOD_END")) {
|
||||||
|
QVariant endTimeVariant = vendingData->getParameter("PERIOD_END");
|
||||||
|
transferData->item.endTime = utils::getISODateTimeWithMsAndOffset(endTimeVariant);
|
||||||
|
transferData->item.insert("ENDTIME", transferData->item.endTime);
|
||||||
|
itemSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("ITEM_PRINT_TEXT")) {
|
||||||
|
QVariant textVariant = vendingData->getParameter("ITEM_PRINT_TEXT");
|
||||||
|
transferData->item.printText = textVariant.toString();
|
||||||
|
transferData->item.insert("PRINTTEXT", transferData->item.printText);
|
||||||
|
itemSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set static data:
|
||||||
|
|
||||||
|
// currency
|
||||||
|
if (itemSet) {
|
||||||
|
transferData->item.currency = this->m_config->getPaymentCurrencyISOCode();
|
||||||
|
transferData->item.insert("CURRENCY", transferData->item.currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemSet) {
|
||||||
|
transferData->insert("ITEM", transferData->item);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////// PAYMENT //////////////////////////////
|
||||||
|
bool paymentSet = false;
|
||||||
|
|
||||||
|
/////////////////////////// PAYMENT.CASH /////////////////////////////
|
||||||
|
if (paymentType == PAYMENT_VARIANTS::TYPE::CASH) {
|
||||||
|
bool cashSet = false;
|
||||||
|
|
||||||
|
if (vendingData->hasParameter("PaymentCashCoins")) {
|
||||||
|
QVariant coins = vendingData->getParameter("PaymentCashCoins");
|
||||||
|
transferData->payment.cash.coins = coins.toInt();
|
||||||
|
transferData->payment.cash.insert("COINS", transferData->payment.cash.coins);
|
||||||
|
cashSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("PaymentCashChange")) {
|
||||||
|
QVariant change = vendingData->getParameter("PaymentCashChange");
|
||||||
|
transferData->payment.cash.change = change.toInt();
|
||||||
|
transferData->payment.cash.insert("CHANGE", transferData->payment.cash.change);
|
||||||
|
cashSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("PaymentCashOverpaid")) {
|
||||||
|
QVariant overpaid = vendingData->getParameter("PaymentCashOverpaid");
|
||||||
|
transferData->payment.cash.overpaid = overpaid.toInt();
|
||||||
|
transferData->payment.cash.insert("OVERPAID", transferData->payment.cash.overpaid);
|
||||||
|
cashSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// currency
|
||||||
|
if (cashSet) {
|
||||||
|
transferData->payment.cash.currency = this->m_config->getPaymentCurrencyISOCode();
|
||||||
|
transferData->payment.cash.insert("CURRENCY", transferData->payment.cash.currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cashSet) {
|
||||||
|
transferData->payment.insert("CASH", transferData->payment.cash);
|
||||||
|
paymentSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////// PAYMENT.CARD /////////////////////////////
|
||||||
|
if (paymentType == PAYMENT_VARIANTS::TYPE::CARD) {
|
||||||
|
paymentSet = true;
|
||||||
|
bool cardSet = true;
|
||||||
|
|
||||||
|
|
||||||
|
transferData->payment.card.insert("CARDNU", "unknown");
|
||||||
|
|
||||||
|
transferData->payment.card.insert("VALUE", transferData->item.price);
|
||||||
|
|
||||||
|
transferData->payment.card.insert("CARDTYPE", "unknown");
|
||||||
|
|
||||||
|
|
||||||
|
transferData->payment.card.currency = this->m_config->getPaymentCurrencyISOCode();
|
||||||
|
transferData->payment.card.insert("CURRENCY", transferData->payment.card.currency);
|
||||||
|
|
||||||
|
// transferData->payment.card.insert("TERMINALID", tid);
|
||||||
|
//transferData->payment.card.insert("TERMINALRESULT", tresult);
|
||||||
|
|
||||||
|
if (cardSet) {
|
||||||
|
transferData->payment.insert("CARD", transferData->payment.card);
|
||||||
|
paymentSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paymentSet) {
|
||||||
|
transferData->insert("PAYMENT", transferData->payment);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////// RESULT /////////////////////////////////
|
||||||
|
bool resultSet = false;
|
||||||
|
|
||||||
|
|
||||||
|
if (vendingData->hasParameter("RESULT_DELIVERY")) {
|
||||||
|
QVariant delVariant = vendingData->getParameter("RESULT_DELIVERY");
|
||||||
|
transferData->result.delivery = delVariant.toJsonValue();
|
||||||
|
transferData->result.insert("DELIVERY", transferData->result.delivery);
|
||||||
|
resultSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("RESULT_RESULT")) {
|
||||||
|
QVariant resVariant = vendingData->getParameter("RESULT_RESULT");
|
||||||
|
transferData->result.result = resVariant.toJsonValue();
|
||||||
|
transferData->result.insert("RESULT", transferData->result.result);
|
||||||
|
resultSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("RESULT_ERROR_CODE")) {
|
||||||
|
QVariant ecVariant = vendingData->getParameter("RESULT_ERROR_CODE");
|
||||||
|
transferData->result.errorCode = ecVariant.toJsonValue();
|
||||||
|
transferData->result.insert("ERRORCODE", transferData->result.errorCode);
|
||||||
|
resultSet = true;
|
||||||
|
}
|
||||||
|
if (vendingData->hasParameter("RESULT_ERROR_MESSAGE")) {
|
||||||
|
QVariant emsgVariant = vendingData->getParameter("RESULT_ERROR_MESSAGE");
|
||||||
|
transferData->result.errorMsg = emsgVariant.toJsonValue();
|
||||||
|
transferData->result.insert("ERRORMSG", transferData->result.errorMsg);
|
||||||
|
resultSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultSet) {
|
||||||
|
transferData->insert("RESULT", transferData->result);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc(*transferData);
|
||||||
|
QByteArray data = "#M=APISM#C=CMD_TRANSACTION#J=";
|
||||||
|
data += jsonDoc.toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
|
this->apismTcpSendClient->sendData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ApismClient::sendAccount(const QHash<QString, QVariant> & accountDataHash)
|
||||||
|
{
|
||||||
|
QScopedPointer<ISMAS::AccountData> accountData(new ISMAS::AccountData());
|
||||||
|
|
||||||
|
accountData->coinBox.UID = QUuid::createUuid().toString(QUuid::WithoutBraces); // .mid(0, 8)
|
||||||
|
accountData->insert("UID", accountData->coinBox.UID);
|
||||||
|
|
||||||
|
accountData->coinBox.ChangeNumber = QJsonValue(static_cast<qint32>(this->persistentData->getNewCoinboxChangeNumber()));
|
||||||
|
accountData->insert("COINBOX_CHANGE_NUMBER", accountData->coinBox.ChangeNumber);
|
||||||
|
|
||||||
|
accountData->coinBox.Process = "COINBOX_CHANGE";
|
||||||
|
accountData->insert("PROCESS", accountData->coinBox.Process);
|
||||||
|
|
||||||
|
accountData->insert("StartTime", utils::getISODateTimeWithMsAndOffset(persistentData->getAccountStartTime()));
|
||||||
|
accountData->insert("EndTime", utils::getCurrentISODateTimeWithMsAndOffset());
|
||||||
|
accountData->insert("StartHash", persistentData->getFirstTransactionUID());
|
||||||
|
accountData->insert("EndHash", persistentData->getLastTransactionUID());
|
||||||
|
|
||||||
|
// coins
|
||||||
|
int numberOfCoinVariants = accountDataHash["NumberOfCoinVariants"].toInt();
|
||||||
|
for (int i=0; i < numberOfCoinVariants;++i) {
|
||||||
|
accountData->coinBox.coin.value = accountDataHash["COIN_" + QString::number(i) + "_Value"].toInt();
|
||||||
|
accountData->coinBox.coin.numberOfCoins = accountDataHash["COIN_" + QString::number(i) + "_Quantity"].toInt();
|
||||||
|
accountData->coinBox.coin.insert("VALUE", accountData->coinBox.coin.value);
|
||||||
|
accountData->coinBox.coin.insert("QUANTITY", accountData->coinBox.coin.numberOfCoins);
|
||||||
|
|
||||||
|
if (accountDataHash.contains("COIN_" + QString::number(i) + "_Currency")) {
|
||||||
|
accountData->coinBox.coin.currency = accountDataHash["COIN_" + QString::number(i) + "_Currency"].toString();
|
||||||
|
accountData->coinBox.coin.insert("CURRENCY", accountData->coinBox.coin.numberOfCoins);
|
||||||
|
}
|
||||||
|
|
||||||
|
accountData->insert("COIN_" + QString::number(i), accountData->coinBox.coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc(*accountData);
|
||||||
|
QByteArray data = "#M=APISM#C=CMD_CashboxChange#J=";
|
||||||
|
data += jsonDoc.toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
|
this->apismTcpSendClient->sendData(data);
|
||||||
|
|
||||||
|
this->persistentData->clearForNewAccount();
|
||||||
|
|
||||||
|
persistentData->serializeToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ApismClient::sendEvent(const ATBMachineEvent* machineEvent)
|
||||||
|
{
|
||||||
|
QScopedPointer<ISMAS::EventData> eventData(new ISMAS::EventData());
|
||||||
|
|
||||||
|
eventData->machineEvent.eventID = machineEvent->eventId;
|
||||||
|
eventData->insert("EVENT_ID", eventData->machineEvent.eventID);
|
||||||
|
|
||||||
|
eventData->machineEvent.deviceName = machineEvent->deviceName;
|
||||||
|
eventData->insert("DeviceName", eventData->machineEvent.deviceName);
|
||||||
|
|
||||||
|
eventData->machineEvent.reason = ATBMachineEvent::getEventClassString(machineEvent->machineEventClass);
|
||||||
|
eventData->insert("Reason", eventData->machineEvent.reason);
|
||||||
|
|
||||||
|
eventData->machineEvent.event = machineEvent->eventName;
|
||||||
|
eventData->insert("Event", eventData->machineEvent.event);
|
||||||
|
|
||||||
|
eventData->machineEvent.eventState = machineEvent->eventState;
|
||||||
|
eventData->insert("EventState", eventData->machineEvent.eventState);
|
||||||
|
|
||||||
|
eventData->machineEvent.timeStamp = machineEvent->timestamString;
|
||||||
|
eventData->insert("Timestamp", eventData->machineEvent.timeStamp);
|
||||||
|
|
||||||
|
eventData->machineEvent.parameter = machineEvent->parameterString;
|
||||||
|
eventData->insert("Parameter", eventData->machineEvent.parameter);
|
||||||
|
|
||||||
|
eventData->machineEvent.secondLevelInfo = machineEvent->secondLevelInfoString;
|
||||||
|
eventData->insert("SecondLevelInfo", eventData->machineEvent.secondLevelInfo);
|
||||||
|
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc(*eventData);
|
||||||
|
QByteArray data = "#M=APISM#C=CMD_EVENT#J=";
|
||||||
|
data += jsonDoc.toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
|
this->apismTcpSendClient->sendData(data);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ApismClient::sendState(const QString & state, const QString & msg)
|
||||||
|
{
|
||||||
|
qCritical() << "ApismClient::sendState(): ";
|
||||||
|
qCritical() << " state: " << state;
|
||||||
|
qCritical() << " msg: " << msg;
|
||||||
|
|
||||||
|
|
||||||
|
QJsonParseError parseError;
|
||||||
|
QJsonDocument document(QJsonDocument::fromJson(msg.toUtf8(), &parseError));
|
||||||
|
if (parseError.error != QJsonParseError::NoError) {
|
||||||
|
qCritical() << "ApismClient::sendState() invalid json msg: Parsing failed:" << parseError.error << parseError.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!document.isObject()) {
|
||||||
|
qCritical() << "File is not JSON object!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QScopedPointer<ISMAS::StateData> stateData(new ISMAS::StateData());
|
||||||
|
|
||||||
|
QJsonObject stateObject = document.object();
|
||||||
|
|
||||||
|
QJsonArray statesArray;
|
||||||
|
statesArray.append(stateObject);
|
||||||
|
|
||||||
|
// stateData->insert("TIMESTAMP", utils::getCurrentISODateTimeWithMsAndOffset());
|
||||||
|
// stateData->insert("HW_States", statesArray);
|
||||||
|
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc(*stateData);
|
||||||
|
QByteArray data = "#M=APISM#C=CMD_HW_STATUS#J=";
|
||||||
|
data += jsonDoc.toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
|
this->apismTcpSendClient->sendData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ApismClient::sendMininformStartRequest(const VendingData* vendingData)
|
||||||
|
{
|
||||||
|
this->currentRequest = ISMAS::REQUEST::START;
|
||||||
|
|
||||||
|
struct MininFormTransferData : public QJsonObject {
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue uid; // MUST: uuid -> vendorId
|
||||||
|
QJsonValue posid; // terminal-id
|
||||||
|
QJsonValue authCode; // approval-code
|
||||||
|
QJsonValue stan; // MUST
|
||||||
|
QJsonValue lpn;
|
||||||
|
QJsonValue transactionTime; // MUST: Zeitstempel Verkauf
|
||||||
|
QJsonValue parkingStartTime; // MUST: Startzeit
|
||||||
|
QJsonValue preAuthAmount;
|
||||||
|
QJsonValue hourlyRate;
|
||||||
|
QJsonValue vehicleCategory;
|
||||||
|
QJsonValue langCode;
|
||||||
|
QJsonValue zoneCode;
|
||||||
|
} startAction;
|
||||||
|
};
|
||||||
|
|
||||||
|
QScopedPointer<MininFormTransferData> transferData(new MininFormTransferData());
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
transferData->startAction.uid = vendingData->getParameter("START_UID").toJsonValue();
|
||||||
|
this->currentRequestUid = vendingData->getParameter("START_UID").toString();
|
||||||
|
transferData->startAction.insert("UID", transferData->startAction.uid);
|
||||||
|
|
||||||
|
transferData->startAction.insert("POSID", vendingData->getParameter("START_POSID").toString());
|
||||||
|
|
||||||
|
transferData->startAction.insert("AUTHCODE", vendingData->getParameter("START_AuthCode").toString());
|
||||||
|
|
||||||
|
transferData->startAction.insert("STAN", vendingData->getParameter("START_STAN").toString());
|
||||||
|
|
||||||
|
transferData->startAction.insert("LPN", vendingData->getParameter("LICENSEPLATE").toString());
|
||||||
|
|
||||||
|
transferData->startAction.insert("TRANSACTIONTIME", utils::getISODateTimeWithMsAndOffset(vendingData->getParameter("START_TRANSACTIONTIME").toString()));
|
||||||
|
|
||||||
|
transferData->startAction.insert("STARTTIME", utils::getISODateTimeWithMsAndOffset(vendingData->getParameter("START_STARTTIME").toString()));
|
||||||
|
|
||||||
|
transferData->startAction.insert("AMOUNT", static_cast<int>(vendingData->getUintParameter("PRICE_INFO_GROSS")));
|
||||||
|
|
||||||
|
transferData->startAction.insert("RATE_H", static_cast<int>(vendingData->getUintParameter("PRICE_INFO_RATE_H")));
|
||||||
|
|
||||||
|
transferData->startAction.insert("VEHICLETYPE", "01"); // Fixed value
|
||||||
|
|
||||||
|
transferData->startAction.insert("LANGUAGE", "HUN"); // Fixed value
|
||||||
|
|
||||||
|
transferData->startAction.insert("ZONE", vendingData->getParameter("MININFORM_ZONE").toString());
|
||||||
|
|
||||||
|
transferData->insert("STARTACTION", transferData->startAction);
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc(*transferData);
|
||||||
|
QByteArray data = "#M=APISM#C=REQ_START#J="; // REQ_... -> use port 7778
|
||||||
|
data += jsonDoc.toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
|
this->apismTcpRequestResponseClient->sendData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismClient::sendMininformStopRequest(const VendingData* vendingData)
|
||||||
|
{
|
||||||
|
this->currentRequest = ISMAS::REQUEST::STOP;
|
||||||
|
|
||||||
|
struct MininFormTransferData : public QJsonObject {
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonObject uid; // MUST: uuid
|
||||||
|
QJsonObject posid; // terminal-id
|
||||||
|
QJsonObject stan; // MUST
|
||||||
|
QJsonObject lpn; // MUST
|
||||||
|
QJsonObject stopTime; // MUST: Stop-Zeit
|
||||||
|
QJsonObject langCode;
|
||||||
|
QJsonObject deviceId;
|
||||||
|
} stopAction;
|
||||||
|
};
|
||||||
|
|
||||||
|
QScopedPointer<MininFormTransferData> transferData(new MininFormTransferData());
|
||||||
|
|
||||||
|
this->currentRequestUid = QUuid::createUuid().toString(QUuid::WithoutBraces).mid(0, 8);
|
||||||
|
transferData->stopAction.insert("UID", this->currentRequestUid);
|
||||||
|
|
||||||
|
transferData->stopAction.insert("POSID", vendingData->getParameter("STOP_POSID").toString());
|
||||||
|
|
||||||
|
transferData->stopAction.insert("STAN", vendingData->getParameter("STOP_STAN").toString());
|
||||||
|
|
||||||
|
transferData->stopAction.insert("LPN", vendingData->getParameter("LICENSEPLATE").toString());
|
||||||
|
|
||||||
|
transferData->stopAction.insert("STOPTIME", utils::getISODateTimeWithMsAndOffset(vendingData->getParameter("STOP_STOPTIME")));
|
||||||
|
|
||||||
|
transferData->stopAction.insert("LANGUAGE", "HUN"); // Fixed value
|
||||||
|
|
||||||
|
transferData->stopAction.insert("DEVICE_ID", this->m_config->getMachineNr());
|
||||||
|
|
||||||
|
transferData->insert("STOPACTION", transferData->stopAction);
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc(*transferData);
|
||||||
|
QByteArray data = "#M=APISM#C=REQ_STOP#J="; // REQ_ -> use port 7778
|
||||||
|
data += jsonDoc.toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
|
this->apismTcpRequestResponseClient->sendData(data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ApismClient::sendSelfTest()
|
||||||
|
{
|
||||||
|
this->currentRequest = ISMAS::REQUEST::SELF;
|
||||||
|
|
||||||
|
QByteArray data = "#M=APISM#C=REQ_SELF#J={}";
|
||||||
|
|
||||||
|
this->apismTcpRequestResponseClient->sendData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismClient::sendMininformPingRequest()
|
||||||
|
{
|
||||||
|
this->currentRequest = ISMAS::REQUEST::PING;
|
||||||
|
|
||||||
|
QByteArray data = "#M=APISM#C=REQ_Ping#J={\"281\":\"PING\"}";
|
||||||
|
|
||||||
|
this->apismTcpRequestResponseClient->sendData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ApismClient::onReceivedResponse(QByteArray response)
|
||||||
|
{
|
||||||
|
// get the root object
|
||||||
|
QJsonParseError jsonParseError;
|
||||||
|
QJsonDocument responseDoc = QJsonDocument::fromJson(response, &jsonParseError);
|
||||||
|
|
||||||
|
if (jsonParseError.error != QJsonParseError::NoError) {
|
||||||
|
qCritical() << "ApismClient::onReceivedResponse() response is no json data:";
|
||||||
|
qCritical() << " Error: " << jsonParseError.errorString();
|
||||||
|
this->handleISMASResponseError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject rootObject = responseDoc.object();
|
||||||
|
|
||||||
|
QStringList rootObjectKeys = rootObject.keys();
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
qCritical() << "ApismClient::onReceivedResponse(): objects: " << rootObjectKeys;
|
||||||
|
// results to:
|
||||||
|
// ApismClient::onReceivedResponse(): objects: ("REQ_START#60044_Response", "Response")
|
||||||
|
|
||||||
|
|
||||||
|
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_START.*")) >= 0) {
|
||||||
|
this->private_handleMininformStartResponse(rootObject["Response"].toObject());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_STOP.*")) >= 0) {
|
||||||
|
this->private_handleMininformStopResponse(rootObject["Response"].toObject());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_SELF.*")) >= 0) {
|
||||||
|
this->private_handleReqSelfResponse(rootObject["Response"].toObject());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_PING.*")) >= 0) {
|
||||||
|
this->private_handleReqPingResponse(rootObject["PING"].toObject());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qCritical() << "ApismClient::onReceivedResponse() for unknown Request: ";
|
||||||
|
qCritical() << " currentRequestName: " << currentRequest;
|
||||||
|
qCritical() << " rootObject.keys(): " << rootObjectKeys;
|
||||||
|
this->handleISMASResponseError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismClient::handleISMASResponseError()
|
||||||
|
{
|
||||||
|
switch (this->currentRequest) {
|
||||||
|
case ISMAS::REQUEST::NO_REQUEST:
|
||||||
|
qCritical() << "ApismClient::onReceivedResponse() for unknown Request: " << currentRequest;
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::START:
|
||||||
|
emit this->sendMininformStartResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::STOP:
|
||||||
|
emit this->sendMininformStopResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::PING:
|
||||||
|
emit this->sendMininformPingResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::SELF:
|
||||||
|
emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::ERROR_BACKEND, QJsonObject());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{\r\n \"REQ_START#53365_Response\": {\r\n \"Aknoledge\": \"OK\"\r\n },
|
||||||
|
\r\n \"Response\": {\r\n \"Result\": \"ERR:Ung<6E>ltiger Datums-String: \"\r\n }\r\n}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
: ISMAS received: "{\r\n \"REQ_PING#30844_Response\": {\r\n \"Aknoledge\": \"OK\"\r\n },
|
||||||
|
"PING": { "IsAviable": "TRUE" }
|
||||||
|
}"
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ApismClient::onSendClientResponseTimeout()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismClient::onRequestResponseClientResponseTimeout()
|
||||||
|
{
|
||||||
|
switch (this->currentRequest) {
|
||||||
|
case ISMAS::REQUEST::NO_REQUEST:
|
||||||
|
qCritical() << "ApismClient::onRequestResponseClientResponseTimeout() for unknown Request: " << currentRequest;
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::START:
|
||||||
|
emit this->sendMininformStartResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::STOP:
|
||||||
|
emit this->sendMininformStopResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::PING:
|
||||||
|
emit this->sendMininformPingResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::SELF:
|
||||||
|
emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::ERROR_TIMEOUT, QJsonObject());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ApismClient::private_handleMininformStartResponse(QJsonObject response)
|
||||||
|
{
|
||||||
|
emit this->sendMininformStartResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismClient::private_handleMininformStopResponse(QJsonObject response)
|
||||||
|
{
|
||||||
|
emit this->sendMininformStopResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismClient::private_handleReqSelfResponse(QJsonObject response)
|
||||||
|
{
|
||||||
|
emit this->sendReqSelfResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismClient::private_handleReqPingResponse(QJsonObject response)
|
||||||
|
{
|
||||||
|
emit this->sendMininformPingResponse(nsApismInterface::RESULT_STATE::SUCCESS, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* operators
|
||||||
|
*/
|
||||||
|
QDebug operator<< (QDebug debug, ISMAS::REQUEST request)
|
||||||
|
{
|
||||||
|
switch(request) {
|
||||||
|
case ISMAS::REQUEST::NO_REQUEST:
|
||||||
|
debug << QString("ISMAS::REQUEST::NO_REQUEST");
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::START:
|
||||||
|
debug << QString("ISMAS::REQUEST::START");
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::STOP:
|
||||||
|
debug << QString("ISMAS::REQUEST::STOP");
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::PING:
|
||||||
|
debug << QString("ISMAS::REQUEST::PING");
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::SELF:
|
||||||
|
debug << QString("ISMAS::REQUEST::SELF");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString& operator<< (QString& str, ISMAS::REQUEST request)
|
||||||
|
{
|
||||||
|
switch(request) {
|
||||||
|
case ISMAS::REQUEST::NO_REQUEST:
|
||||||
|
str = QString("ISMAS::REQUEST::NO_REQUEST");
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::START:
|
||||||
|
str = QString("ISMAS::REQUEST::START");
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::STOP:
|
||||||
|
str = QString("ISMAS::REQUEST::STOP");
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::PING:
|
||||||
|
str = QString("ISMAS::REQUEST::PING");
|
||||||
|
break;
|
||||||
|
case ISMAS::REQUEST::SELF:
|
||||||
|
str = QString("ISMAS::REQUEST::SELF");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
120
apism/apism_client.h
Normal file
120
apism/apism_client.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#ifndef APISM_CLIENT_H_INCLUDED
|
||||||
|
#define APISM_CLIENT_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "ismas_data.h"
|
||||||
|
#include "apism_tcp_client.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QJsonValue>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, ISMAS::REQUEST request);
|
||||||
|
QString& operator<<(QString& str, ISMAS::REQUEST request);
|
||||||
|
|
||||||
|
namespace nsApismInterface {
|
||||||
|
|
||||||
|
enum class RESULT_STATE : quint8 {
|
||||||
|
SUCCESS = 1,
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VendingData;
|
||||||
|
class ATBHMIconfig;
|
||||||
|
class PersistentData;
|
||||||
|
class ATBMachineEvent;
|
||||||
|
class ApismClient : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ApismClient(QObject *eventReceiver, ATBHMIconfig *config, PersistentData *persistentData, QObject *parent = 0);
|
||||||
|
~ApismClient();
|
||||||
|
|
||||||
|
quint32 getLastError();
|
||||||
|
const QString & getLastErrorDescription();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void sendSelfTest();
|
||||||
|
void sendTransaction(const VendingData* vendingData);
|
||||||
|
void sendAccount(const QHash<QString, QVariant> &accountDataHash);
|
||||||
|
void sendEvent(const ATBMachineEvent* machineEvent);
|
||||||
|
|
||||||
|
void sendState(const QString & state, const QString & msg);
|
||||||
|
|
||||||
|
|
||||||
|
void sendMininformStartRequest(const VendingData* vendingData);
|
||||||
|
void sendMininformStopRequest(const VendingData* vendingData);
|
||||||
|
void sendMininformPingRequest();
|
||||||
|
|
||||||
|
void restartApism();
|
||||||
|
|
||||||
|
#ifdef USE_SZEGED_START_STOP
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// public signals:
|
||||||
|
void sendTransactionRespones(nsApismInterface::RESULT_STATE result);
|
||||||
|
void sendAccountResponse(nsApismInterface::RESULT_STATE result);
|
||||||
|
|
||||||
|
|
||||||
|
void sendMininformStartResponse(nsApismInterface::RESULT_STATE result, QJsonObject response);
|
||||||
|
void sendMininformStopResponse(nsApismInterface::RESULT_STATE result, QJsonObject response);
|
||||||
|
void sendMininformPingResponse(nsApismInterface::RESULT_STATE result, QJsonObject response);
|
||||||
|
void sendReqSelfResponse(nsApismInterface::RESULT_STATE result, QJsonObject response);
|
||||||
|
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
// void onSocketError(QAbstractSocket::SocketError socketError);
|
||||||
|
|
||||||
|
void onReceivedResponse(QByteArray response);
|
||||||
|
|
||||||
|
void onSendClientResponseTimeout();
|
||||||
|
void onRequestResponseClientResponseTimeout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QObject *healthEventReceiver;
|
||||||
|
ATBHMIconfig *m_config;
|
||||||
|
|
||||||
|
PersistentData *persistentData;
|
||||||
|
|
||||||
|
ApismTcpClient* apismTcpSendClient;
|
||||||
|
ApismTcpClient* apismTcpRequestResponseClient;
|
||||||
|
|
||||||
|
quint32 lastError;
|
||||||
|
QString lastErrorDescription;
|
||||||
|
|
||||||
|
QString currentRequestUid;
|
||||||
|
ISMAS::REQUEST currentRequest;
|
||||||
|
|
||||||
|
|
||||||
|
void private_handleMininformStartResponse(QJsonObject response);
|
||||||
|
void private_handleMininformStopResponse(QJsonObject response);
|
||||||
|
void private_handlePingResponse(QJsonObject response);
|
||||||
|
void private_handleReqSelfResponse(QJsonObject response);
|
||||||
|
void private_handleReqPingResponse(QJsonObject response);
|
||||||
|
|
||||||
|
void handleISMASResponseError();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Q_DECLARE_METATYPE(QAbstractSocket::SocketError)
|
||||||
|
|
||||||
|
#endif // APISM_CLIENT_H_INCLUDED
|
166
apism/apism_tcp_client.cpp
Normal file
166
apism/apism_tcp_client.cpp
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#include "apism_tcp_client.h"
|
||||||
|
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
ApismTcpClient::ApismTcpClient(const QString & hostname,
|
||||||
|
const QString & port,
|
||||||
|
QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, hostname(hostname)
|
||||||
|
, port(port)
|
||||||
|
, responseTimerTimeoutCounter(0)
|
||||||
|
{
|
||||||
|
this->responseTimeoutTimer = new QTimer(this);
|
||||||
|
this->responseTimeoutTimer->setInterval(10000);
|
||||||
|
this->responseTimeoutTimer->setSingleShot(true);
|
||||||
|
|
||||||
|
connect(this->responseTimeoutTimer, SIGNAL(timeout()), this, SLOT(onResponseTimeoutTimerTimeout()));
|
||||||
|
|
||||||
|
socket = new QTcpSocket(this);
|
||||||
|
connect(socket, SIGNAL(connected()), this, SLOT(onSocketConnected()));
|
||||||
|
connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||||
|
connect(socket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));
|
||||||
|
connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(onSocketBytesWritten(qint64)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ApismTcpClient::connectToHost()
|
||||||
|
{
|
||||||
|
int portNumber = this->port.toInt();
|
||||||
|
this->socket->connectToHost(QHostAddress(this->hostname), portNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismTcpClient::connectToHost(const QString & hostname, const QString & port)
|
||||||
|
{
|
||||||
|
qCritical() << "ApismTcpClient::connectToHost(" << hostname << ", " << port << ")";
|
||||||
|
|
||||||
|
int portNumber = port.toInt();
|
||||||
|
socket->connectToHost(hostname, portNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismTcpClient::closeConnection()
|
||||||
|
{
|
||||||
|
socket->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ApismTcpClient::isConnected()
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
QAbstractSocket::SocketState socketState = socket->state();
|
||||||
|
|
||||||
|
switch (socketState) {
|
||||||
|
case QAbstractSocket::UnconnectedState:
|
||||||
|
/* FALLTHRU */
|
||||||
|
case QAbstractSocket::HostLookupState:
|
||||||
|
/* FALLTHRU */
|
||||||
|
case QAbstractSocket::ConnectingState:
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::ConnectedState:
|
||||||
|
/* FALLTHRU */
|
||||||
|
case QAbstractSocket::BoundState:
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::ClosingState:
|
||||||
|
/* FALLTHRU */
|
||||||
|
case QAbstractSocket::ListeningState:
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ApismTcpClient::sendData(const QByteArray & message)
|
||||||
|
{
|
||||||
|
//qCritical() << "ApismTcpClient::send: " << message;
|
||||||
|
|
||||||
|
this->sendQueue.enqueue(message);
|
||||||
|
|
||||||
|
if (this->isConnected()) {
|
||||||
|
this->private_sendData();
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->connectToHost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ApismTcpClient::private_sendData
|
||||||
|
*
|
||||||
|
* Precondition is that queue is not empty.
|
||||||
|
*/
|
||||||
|
void ApismTcpClient::private_sendData()
|
||||||
|
{
|
||||||
|
// take message from queue
|
||||||
|
QByteArray ba = this->sendQueue.dequeue();
|
||||||
|
|
||||||
|
qCritical() << "ApismTcpClient::send: " << QString(ba);
|
||||||
|
|
||||||
|
socket->write(ba);
|
||||||
|
socket->flush();
|
||||||
|
|
||||||
|
// start timeoutTimer
|
||||||
|
this->responseTimeoutTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismTcpClient::onSocketConnected()
|
||||||
|
{
|
||||||
|
qCritical() << "ApismTcpClient: Connected!";
|
||||||
|
|
||||||
|
if (this->sendQueue.size() > 0) {
|
||||||
|
this->private_sendData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismTcpClient::onSocketDisconnected()
|
||||||
|
{
|
||||||
|
qCritical() << "ApismTcpClient: Disconnected!";
|
||||||
|
qCritical() << " -> SocketErrorString: " << socket->errorString();
|
||||||
|
|
||||||
|
if (this->sendQueue.size() > 0) {
|
||||||
|
this->connectToHost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismTcpClient::onSocketBytesWritten(qint64 bytes)
|
||||||
|
{
|
||||||
|
Q_UNUSED(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApismTcpClient::onSocketReadyRead()
|
||||||
|
{
|
||||||
|
QByteArray readData;
|
||||||
|
|
||||||
|
// stop timeoutTimer
|
||||||
|
this->responseTimeoutTimer->stop();
|
||||||
|
|
||||||
|
readData = socket->readAll();
|
||||||
|
|
||||||
|
qCritical() << "ISMAS received: " << QString(readData);
|
||||||
|
|
||||||
|
emit this->receivedData(readData);
|
||||||
|
|
||||||
|
this->socket->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ApismTcpClient::onResponseTimeoutTimerTimeout()
|
||||||
|
{
|
||||||
|
if (this->sendQueue.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit this->responseTimeout();
|
||||||
|
|
||||||
|
qCritical() << "ApismTcpClient::onResponseTimeoutTimerTimeout() --> skip this message, send next command, if available.";
|
||||||
|
|
||||||
|
// Try next command
|
||||||
|
this->sendQueue.removeFirst();
|
||||||
|
if (this->sendQueue.size() > 0) this->private_sendData();
|
||||||
|
}
|
62
apism/apism_tcp_client.h
Normal file
62
apism/apism_tcp_client.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#ifndef APISMTCPCLIENT_H
|
||||||
|
#define APISMTCPCLIENT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
|
class ApismTcpClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ApismTcpClient(const QString & hostname, const QString & port, QObject *parent = nullptr);
|
||||||
|
bool isConnected();
|
||||||
|
|
||||||
|
void connectToHost();
|
||||||
|
void connectToHost(const QString & hostname, const QString & port);
|
||||||
|
|
||||||
|
// socket is implicitely closed by APISM
|
||||||
|
void closeConnection();
|
||||||
|
|
||||||
|
void sendData(const QByteArray & message);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// socket interface
|
||||||
|
void onSocketConnected();
|
||||||
|
void onSocketDisconnected();
|
||||||
|
void onSocketBytesWritten(qint64 bytes);
|
||||||
|
void onSocketReadyRead();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void receivedData(QByteArray response);
|
||||||
|
|
||||||
|
void responseTimeout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTcpSocket *socket;
|
||||||
|
|
||||||
|
QQueue<QByteArray> sendQueue;
|
||||||
|
|
||||||
|
|
||||||
|
QString hostname;
|
||||||
|
QString port;
|
||||||
|
|
||||||
|
QTimer *responseTimeoutTimer;
|
||||||
|
quint8 responseTimerTimeoutCounter;
|
||||||
|
|
||||||
|
|
||||||
|
void private_sendData();
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onResponseTimeoutTimerTimeout();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // APISMTCPCLIENT_H
|
136
apism/ismas_data.h
Normal file
136
apism/ismas_data.h
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#ifndef ISMASDATA_H
|
||||||
|
#define ISMASDATA_H
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ISMAS {
|
||||||
|
|
||||||
|
struct TransferData : public QJsonObject {
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue tariffId;
|
||||||
|
QJsonValue group;
|
||||||
|
QJsonValue zone;
|
||||||
|
} device;
|
||||||
|
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue state;
|
||||||
|
QJsonValue uid;
|
||||||
|
QJsonValue seq_tick_number;
|
||||||
|
QJsonValue timestamp;
|
||||||
|
QJsonValue userText;
|
||||||
|
QJsonValue userTextType;
|
||||||
|
} transaction;
|
||||||
|
|
||||||
|
struct : public QJsonObject {
|
||||||
|
// TODO: check what is really used at the moment
|
||||||
|
QJsonValue id; // unique article id
|
||||||
|
QJsonValue name; // name
|
||||||
|
QJsonValue price; // price in cent
|
||||||
|
QJsonValue currency; //
|
||||||
|
QJsonValue startTime; // start time
|
||||||
|
QJsonValue endTime; // end time
|
||||||
|
QJsonValue userText; // additional info
|
||||||
|
QJsonValue parkingTime;
|
||||||
|
QJsonValue printText;
|
||||||
|
// QJsonValue discount;
|
||||||
|
} item;
|
||||||
|
|
||||||
|
struct : public QJsonObject {
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue coins; // total amount of coins value
|
||||||
|
// QJsonValue notes; // total amount of notes value
|
||||||
|
QJsonValue overpaid; // in cent
|
||||||
|
QJsonValue currency;
|
||||||
|
QJsonValue change;
|
||||||
|
} cash;
|
||||||
|
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue cardNumber;
|
||||||
|
QJsonValue value; // buchungsbetrag
|
||||||
|
QJsonValue cardType;
|
||||||
|
QJsonValue currency;
|
||||||
|
QJsonValue tid;
|
||||||
|
QJsonValue tresult;
|
||||||
|
} card;
|
||||||
|
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue cardNumber;
|
||||||
|
QJsonValue cardType;
|
||||||
|
QJsonValue value;
|
||||||
|
QJsonValue valueOld;
|
||||||
|
QJsonValue valueNew;
|
||||||
|
QJsonValue time;
|
||||||
|
QJsonValue timeOld;
|
||||||
|
QJsonValue timeNew;
|
||||||
|
} prePaidCard;
|
||||||
|
} payment;
|
||||||
|
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue delivery; // PRINT, OnlineTicket
|
||||||
|
QJsonValue result; // SUCCESS, ERROR
|
||||||
|
QJsonValue errorCode; // 0=OK, 1=...
|
||||||
|
QJsonValue errorMsg;
|
||||||
|
} result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct AccountData : public QJsonObject {
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue UID;
|
||||||
|
QJsonValue ChangeNumber;
|
||||||
|
QJsonValue Process; // Vorgang
|
||||||
|
QJsonValue startDateTime;
|
||||||
|
QJsonValue endDateTime;
|
||||||
|
QJsonValue startHash;
|
||||||
|
QJsonValue endHash;
|
||||||
|
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue value; // coin value
|
||||||
|
QJsonValue numberOfCoins; // number of coins
|
||||||
|
QJsonValue currency;
|
||||||
|
} coin;
|
||||||
|
|
||||||
|
} coinBox; // Münzkasse
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct EventData : public QJsonObject {
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue eventID;
|
||||||
|
QJsonValue deviceName;
|
||||||
|
QJsonValue reason;
|
||||||
|
QJsonValue event;
|
||||||
|
QJsonValue eventState;
|
||||||
|
QJsonValue timeStamp;
|
||||||
|
QJsonValue parameter;
|
||||||
|
QJsonValue secondLevelInfo;
|
||||||
|
} machineEvent; //
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StateData : public QJsonObject {
|
||||||
|
QJsonValue Timestamp;
|
||||||
|
QJsonArray HW_States;
|
||||||
|
struct : public QJsonObject {
|
||||||
|
QJsonValue name;
|
||||||
|
QJsonValue value;
|
||||||
|
QJsonValue unit;
|
||||||
|
} machineState; //
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum class REQUEST : quint8 {
|
||||||
|
NO_REQUEST,
|
||||||
|
START,
|
||||||
|
STOP,
|
||||||
|
PING,
|
||||||
|
SELF
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ISMASDATA_H
|
Loading…
Reference in New Issue
Block a user