Compare commits
39 Commits
61c847102d
...
f963b61ebc
Author | SHA1 | Date | |
---|---|---|---|
f963b61ebc | |||
9ed51d60e4 | |||
f5198efab3 | |||
d6446f90fe | |||
58bceb5d27 | |||
92084bed99 | |||
cd1c92a7db | |||
9ca758ecd3 | |||
3c54d8de6d | |||
d91d4261d9 | |||
00f5216a9f | |||
aeae9002fe | |||
9df425f5f8 | |||
5149a67d4b | |||
1309c27f7c | |||
26db620465 | |||
bd213b8f8c | |||
31b7bd1314 | |||
0bdbd39632 | |||
b979fb5b2a | |||
cbefccd2d3 | |||
0ebe274e9a | |||
c4d09eb2ea | |||
3039fcc553 | |||
a67e587769 | |||
d89520d58e | |||
06a9eba177 | |||
a41dc5403f | |||
85b2c1f08e | |||
ba8dd7d083 | |||
fa04e32266 | |||
7d6b433373 | |||
faae8b8d9a | |||
a0d0de19c5 | |||
17eaa7858f | |||
f2556412d8 | |||
26557542f1 | |||
6bb46e165c | |||
027529161d |
@ -1,16 +1,18 @@
|
||||
# QT -= gui
|
||||
QT += core
|
||||
QT += widgets serialport
|
||||
QT += widgets serialport network
|
||||
# QT += network
|
||||
|
||||
TARGET = ATBUpdateTool
|
||||
|
||||
VERSION=1.0.0
|
||||
|
||||
INCLUDEPATH += plugins
|
||||
|
||||
CONFIG += c++17 console
|
||||
# CONFIG -= app_bundle
|
||||
|
||||
# DEFINES+=LinuxDesktop
|
||||
DEFINES+=APP_VERSION=\\\"$$VERSION\\\"
|
||||
|
||||
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
|
||||
@ -34,7 +36,7 @@ contains( CONFIG, PTU5 ) {
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += serialport
|
||||
CONFIG += link_pkgconfig
|
||||
lessThan(QT_MAJOR_VERSION, 5): PKGCONFIG += qextserialport
|
||||
QMAKE_CXXFLAGS += -std=c++11 # for GCC >= 4.7
|
||||
QMAKE_CXXFLAGS += -std=c++17 # for GCC >= 4.7
|
||||
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
ARCH = PTU5
|
||||
DEFINES+=PTU5
|
||||
@ -53,7 +55,7 @@ contains( CONFIG, DesktopLinux ) {
|
||||
lessThan(QT_MAJOR_VERSION, 5): CONFIG += extserialport
|
||||
# QMAKE_CC = ccache $$QMAKE_CC
|
||||
# QMAKE_CXX = ccache $$QMAKE_CXX
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
QMAKE_CXXFLAGS += -std=c++17
|
||||
QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
linux-clang { QMAKE_CXXFLAGS += -Qunused-arguments }
|
||||
ARCH = DesktopLinux
|
||||
@ -63,12 +65,23 @@ contains( CONFIG, DesktopLinux ) {
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
update.cpp \
|
||||
git/git_client.cpp \
|
||||
apism/apism_client.cpp \
|
||||
apism/apism_tcp_client.cpp \
|
||||
ismas/ismas_client.cpp \
|
||||
process/command.cpp \
|
||||
message_handler.cpp \
|
||||
worker.cpp \
|
||||
worker_thread.cpp
|
||||
|
||||
HEADERS += \
|
||||
update.h \
|
||||
git/git_client.h \
|
||||
apism/apism_client.h \
|
||||
apism/apism_tcp_client.h \
|
||||
apism/ismas_data.h \
|
||||
ismas/ismas_client.h \
|
||||
process/command.h \
|
||||
message_handler.h \
|
||||
worker.h \
|
||||
worker_thread.h \
|
||||
|
811
apism/apism_client.cpp
Normal file
811
apism/apism_client.cpp
Normal file
@ -0,0 +1,811 @@
|
||||
#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::requestAvailableIsmasUpdates() {
|
||||
QByteArray data = "#M=APISM #C=REQ_ISMASParameter #J={}";
|
||||
this->currentRequest = ISMAS::REQUEST::ISMAS_PARAMETER;
|
||||
this->apismTcpRequestResponseClient->sendData(data);
|
||||
}
|
||||
|
||||
void ApismClient::sendCmdSendVersionToIsmas(QString const &msg) {
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument document(QJsonDocument::fromJson(msg.toUtf8(), &parseError));
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qCritical() << "INVALID JSON MSG: PARSING FAILED:"
|
||||
<< parseError.error << parseError.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!document.isObject()) {
|
||||
qCritical() << "FILE IS NOT A JSON OBJECT!";
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = "#M=APISM#C=CMD_SENDVERSION#J=";
|
||||
data += document.toJson(QJsonDocument::Compact);
|
||||
|
||||
printf("data=%s\n", QString(data).toStdString().c_str());
|
||||
|
||||
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||||
this->apismTcpSendClient->sendData(data);
|
||||
|
||||
}
|
||||
|
||||
void ApismClient::sendUpdateInfoToIsmas(QString const &msg) {
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument document(QJsonDocument::fromJson(msg.toUtf8(), &parseError));
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qCritical() << "INVALID JSON MSG: PARSING FAILED:"
|
||||
<< parseError.error << parseError.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!document.isObject()) {
|
||||
qCritical() << "FILE IS NOT A JSON OBJECT!";
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = "#M=APISM#C=CMD_EVENT#J=";
|
||||
data += document.toJson(QJsonDocument::Compact);
|
||||
|
||||
printf("data=%s\n", QString(data).toStdString().c_str());
|
||||
|
||||
this->currentRequest = ISMAS::REQUEST::NO_REQUEST;
|
||||
this->apismTcpSendClient->sendData(data);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
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());
|
||||
|
||||
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() {
|
||||
qDebug() << "SENDING APISM-SELF-TEST";
|
||||
this->currentRequest = ISMAS::REQUEST::SELF;
|
||||
QByteArray data = "#M=APISM#C=REQ_SELF#J={}";
|
||||
this->apismTcpRequestResponseClient->sendData(data);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void ApismClient::sendMininformPingRequest()
|
||||
{
|
||||
this->currentRequest = ISMAS::REQUEST::PING;
|
||||
|
||||
QByteArray data = "#M=APISM#C=REQ_Ping#J={\"281\":\"PING\"}";
|
||||
|
||||
this->apismTcpRequestResponseClient->sendData(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void ApismClient::onReceivedResponse(QByteArray response) {
|
||||
if (this->currentRequest == ISMAS::REQUEST::NO_REQUEST &&
|
||||
response == "RECORD SAVED") { // sent by APISM to indicate that record
|
||||
return; // has been saved in DB
|
||||
}
|
||||
|
||||
// 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
|
||||
qDebug() << "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
|
||||
if(rootObjectKeys.indexOf(QRegularExpression("^REQ_ISMASPARAMETER.*")) >= 0) {
|
||||
this->private_handleIsmasParameterResponse(rootObject);
|
||||
}
|
||||
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;
|
||||
case ISMAS::REQUEST::ISMAS_PARAMETER:
|
||||
// TODO
|
||||
// emit
|
||||
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;
|
||||
case ISMAS::REQUEST::ISMAS_PARAMETER:
|
||||
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);
|
||||
}
|
||||
|
||||
void ApismClient::private_handleIsmasParameterResponse(QJsonObject response) {
|
||||
emit this->ismasResponseAvailable(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;
|
||||
case ISMAS::REQUEST::ISMAS_PARAMETER:
|
||||
debug << QString("ISMAS::REQUEST::ISMASPARAMETER");
|
||||
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;
|
||||
case ISMAS::REQUEST::ISMAS_PARAMETER:
|
||||
str = QString("ISMAS::REQUEST::ISMASPARAMETER");
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
122
apism/apism_client.h
Normal file
122
apism/apism_client.h
Normal file
@ -0,0 +1,122 @@
|
||||
#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 sendUpdateInfoToIsmas(QString const &msg);
|
||||
void sendCmdSendVersionToIsmas(QString const &msg);
|
||||
void requestAvailableIsmasUpdates();
|
||||
|
||||
|
||||
//void sendMininformStartRequest(const VendingData* vendingData);
|
||||
//void sendMininformStopRequest(const VendingData* vendingData);
|
||||
//void sendMininformPingRequest();
|
||||
|
||||
void restartApism();
|
||||
|
||||
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);
|
||||
|
||||
void ismasResponseAvailable(QJsonObject ismasResponse);
|
||||
|
||||
|
||||
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 private_handleIsmasParameterResponse(QJsonObject response);
|
||||
|
||||
void handleISMASResponseError();
|
||||
|
||||
};
|
||||
|
||||
// Q_DECLARE_METATYPE(QAbstractSocket::SocketError)
|
||||
|
||||
#endif // APISM_CLIENT_H_INCLUDED
|
172
apism/apism_tcp_client.cpp
Normal file
172
apism/apism_tcp_client.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
#include "apism_tcp_client.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QTimer>
|
||||
#include <QCoreApplication>
|
||||
|
||||
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() {
|
||||
qCritical() << "ApismTcpClient::connectToHost(this->" << hostname << ", " << port << ")";
|
||||
int portNumber = this->port.toInt();
|
||||
this->socket->connectToHost(QHostAddress(this->hostname), portNumber);
|
||||
if (!socket->waitForConnected(10000)) {
|
||||
qCritical() << "ERROR IN WAIT FOR CONNECTED" << socket->errorString();
|
||||
} else {
|
||||
qDebug() << "connected to" << hostname << ", " << port << ")";
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
qDebug() << "ApismTcpClient::send: " << message;
|
||||
|
||||
this->sendQueue.enqueue(message);
|
||||
|
||||
if (this->isConnected()) {
|
||||
qCritical() << "ApismTcpClient::send: connected, send" << message;
|
||||
this->private_sendData();
|
||||
} else {
|
||||
qCritical() << "ApismTcpClient::send: not connected, connect";
|
||||
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();
|
||||
|
||||
qDebug() << "ApismTcpClient::send: " << QString(ba);
|
||||
|
||||
socket->write(ba);
|
||||
socket->flush();
|
||||
|
||||
// start timeoutTimer
|
||||
this->responseTimeoutTimer->start();
|
||||
}
|
||||
|
||||
void ApismTcpClient::onSocketConnected()
|
||||
{
|
||||
qInfo() << "ApismTcpClient: Connected!";
|
||||
|
||||
if (this->sendQueue.size() > 0) {
|
||||
this->private_sendData();
|
||||
}
|
||||
}
|
||||
|
||||
void ApismTcpClient::onSocketDisconnected()
|
||||
{
|
||||
qDebug() << "ApismTcpClient: Disconnected!";
|
||||
qDebug() << " -> 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();
|
||||
|
||||
qDebug() << "ISMAS received: " << QString(readData);
|
||||
|
||||
emit this->receivedData(readData);
|
||||
//QCoreApplication::processEvents();
|
||||
|
||||
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
|
137
apism/ismas_data.h
Normal file
137
apism/ismas_data.h
Normal file
@ -0,0 +1,137 @@
|
||||
#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,
|
||||
ISMAS_PARAMETER
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // ISMASDATA_H
|
319
git/git_client.cpp
Normal file
319
git/git_client.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
#include "git_client.h"
|
||||
#include "update.h"
|
||||
#include "worker.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
||||
|
||||
GitClient::GitClient(QString const &repositoryPath,
|
||||
QString const &customerId,
|
||||
QString const &workingDirectory,
|
||||
QString const &branchName,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_worker(qobject_cast<Worker *>(parent))
|
||||
, m_repositoryPath(repositoryPath)
|
||||
, m_customerId(customerId)
|
||||
, m_workingDirectory(workingDirectory)
|
||||
, m_branchName(branchName)
|
||||
, m_customerRepository(QDir::cleanPath(m_workingDirectory
|
||||
+ QDir::separator()
|
||||
+ m_customerId)) {
|
||||
if (!m_worker) {
|
||||
qCritical() << "ERROR CASTING PARENT TO WORKER FAILED";
|
||||
}
|
||||
|
||||
connect(this, SIGNAL(ismasUpdatesAvailable()),
|
||||
this, SLOT(onIsmasUpdatesAvailable()), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void GitClient::onIsmasUpdatesAvailable() {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
qInfo() << "FETCHING OF" << m_repositoryPath
|
||||
<< "INTO" << m_customerRepository;
|
||||
std::optional<QString> changes = gitFetch();
|
||||
if (changes) {
|
||||
std::optional<QStringList> changedFileNames = gitDiff(changes.value());
|
||||
if (changedFileNames) {
|
||||
for (int i=0;i<changedFileNames.value().size();++i) {
|
||||
QString fname = changedFileNames.value().at(i);
|
||||
QString lastCommit = gitLastCommit(fname);
|
||||
qDebug() << "CCCC" << changedFileNames.value().at(i) << lastCommit;
|
||||
}
|
||||
if (gitPull()) {
|
||||
emit m_worker->handleChangedFiles(changedFileNames.value());
|
||||
} else {
|
||||
qCritical() << "PULL FAILED FOR" << m_repositoryPath
|
||||
<< "IN " << m_customerRepository;
|
||||
emit m_worker->terminateUpdateProcess();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "NO CHANGES IN" << m_repositoryPath
|
||||
<< "(" << m_customerRepository << ")";
|
||||
emit m_worker->finishUpdateProcess(false);
|
||||
}
|
||||
} else {
|
||||
qCritical() << "NO CHANGES IN" << m_repositoryPath
|
||||
<< "(" << m_customerRepository << ")";
|
||||
emit m_worker->finishUpdateProcess(false);
|
||||
}
|
||||
} else {
|
||||
if (gitCloneAndCheckoutBranch()) {
|
||||
qInfo() << "CLONED" << m_repositoryPath
|
||||
<< "AND CHECKED OUT INTO" << m_customerRepository;
|
||||
if (m_worker) {
|
||||
qDebug() << "WORKER EXECUTE OPKG COMMANDS";
|
||||
QStringList opkgCommands;
|
||||
// To make sure that opkg upgrade does not break your system
|
||||
// because of an unstable connection
|
||||
// Add a line "option cache cachedir" to /etc/opkg/opkg.conf to
|
||||
// avoid the --cache option on command line.
|
||||
opkgCommands << "opkg update";
|
||||
//opkgCommands << "opkg --cache cachedir --download-only upgrade";
|
||||
//opkgCommands << "opkg --cache cachedir upgrade";
|
||||
emit m_worker->executeOpkgCommands(opkgCommands);
|
||||
}
|
||||
} else {
|
||||
qCritical() << "ERROR CLONING " << m_repositoryPath
|
||||
<< "AND/OR CHECKING OUT INTO" << m_customerRepository;
|
||||
emit m_worker->terminateUpdateProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GitClient::gitCloneCustomerRepository() {
|
||||
QString gitCommand("git clone ");
|
||||
gitCommand += m_repositoryPath;
|
||||
Command c(gitCommand);
|
||||
|
||||
qInfo() << "IN CURRENT WD" << m_workingDirectory
|
||||
<< "CLONE" << m_repositoryPath << "...";
|
||||
|
||||
if (c.execute(m_workingDirectory)) { // execute the command in wd
|
||||
QString result = c.getCommandResult();
|
||||
if (!result.isEmpty()) {
|
||||
// Cloning into 'customer_281'...\n
|
||||
static QRegularExpression re("(^\\s*Cloning\\s+into\\s+[']\\s*)(.*)(\\s*['].*$)");
|
||||
QRegularExpressionMatch match = re.match(result);
|
||||
if (match.hasMatch()) {
|
||||
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
||||
if (match.captured(2).trimmed() == m_customerId) {
|
||||
qInfo() << "CLONING" << m_repositoryPath << "OK";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
qCritical() << "ERROR CLONE RESULT HAS WRONG FORMAT";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GitClient::copyGitConfigFromMaster() { // only allowed when called in
|
||||
// master branch
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
QString const cp = QString("cp .gitconfig .git/config");
|
||||
Command c("bash");
|
||||
if (c.execute(m_customerRepository, QStringList() << "-c" << cp)) {
|
||||
qInfo() << "cp .gitconfig .git/config OK";
|
||||
return true;
|
||||
}
|
||||
qCritical() << "ERROR cp .gitconfig .git/config";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GitClient::gitCheckoutBranch() {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
QString gitCommand("git checkout ");
|
||||
gitCommand += m_branchName;
|
||||
Command c(gitCommand);
|
||||
return c.execute(m_customerRepository); // execute command in customerRepo
|
||||
}
|
||||
qCritical() << "ERROR" << m_customerRepository << "DOES NOT EXIST";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GitClient::gitCloneAndCheckoutBranch() {
|
||||
qInfo() << "CLONE" << m_repositoryPath << "AND CHECKOUT" << m_branchName;
|
||||
if (gitCloneCustomerRepository()) {
|
||||
if (copyGitConfigFromMaster()) {
|
||||
return gitCheckoutBranch();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Zu beachten: wird eine datei neu hinzugefuegt (git add/commit) dann aber gleich
|
||||
wieder geloscht, so wird sie im diff nicht angezeigt.
|
||||
*/
|
||||
std::optional<QStringList> GitClient::gitDiff(QString const &commits) {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
// 409f198..6c22726
|
||||
QString gitCommand("git diff --compact-summary ");
|
||||
gitCommand += commits;
|
||||
|
||||
Command c(gitCommand);
|
||||
if (c.execute(m_customerRepository)) { // execute command in local customerRepo
|
||||
QString s = c.getCommandResult().trimmed();
|
||||
QStringList lines = Update::split(s, '\n');
|
||||
QStringList fileNames;
|
||||
// each line has the format "etc/psa_config/DC2C_print01.json | 1 +
|
||||
// or the format "etc/psa_config/DC2C_print01.json (new) | 1 +
|
||||
// the filenames are relativ to the repository
|
||||
for (int i = 0; i < lines.size(); ++i) {
|
||||
// TODO: koennte auch (delete) kommen ?
|
||||
int newIndex = lines.at(i).indexOf("(new)"); // for new files
|
||||
// int goneIndex = lines.at(i).indexOf("(gone)"); // for removed files
|
||||
if (newIndex != -1) {
|
||||
QString fileName = lines.at(i).mid(0, newIndex).trimmed();
|
||||
fileNames << fileName;
|
||||
} else {
|
||||
int pipeIndex = lines.at(i).indexOf('|');
|
||||
if (pipeIndex != -1) {
|
||||
QString fileName = lines.at(i).mid(0, pipeIndex).trimmed();
|
||||
fileNames << fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fileNames.isEmpty()) {
|
||||
return fileNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/*
|
||||
Hat sich nichts geaendert, so werden auch keine Commits <>..<> angezeigt
|
||||
*/
|
||||
std::optional<QString> GitClient::gitFetch() {
|
||||
QString const &customerRepository
|
||||
= QDir::cleanPath(m_workingDirectory + QDir::separator() + m_customerId);
|
||||
if (QDir(customerRepository).exists()) {
|
||||
Command c("git fetch");
|
||||
if (c.execute(customerRepository)) {
|
||||
QString const s = c.getCommandResult().trimmed();
|
||||
if (!s.isEmpty()) {
|
||||
QStringList lines = Update::split(s, '\n');
|
||||
if (!lines.empty()) {
|
||||
// 409f198..6c22726 zg1/zone1 -> origin/zg1/zone1
|
||||
static QRegularExpression re("(^\\s*)([0-9A-Fa-f]+..[0-9A-Fa-f]+)(.*$)");
|
||||
QRegularExpressionMatch match = re.match(lines.last());
|
||||
if (match.hasMatch()) {
|
||||
if (re.captureCount() == 3) { // start with full match (0), then the other 3 matches
|
||||
return match.captured(2);
|
||||
} else {
|
||||
qCritical() << "ERROR WRONG CAPTURE COUNT FOR 'GIT FETCH'" << re.captureCount();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "ERROR NO MATCH OF COMMITS FOR 'GIT FETCH'";
|
||||
}
|
||||
} else {
|
||||
qCritical() << "ERROR WRONG FORMAT FOR RESULT FOR 'GIT FETCH'" << s;
|
||||
}
|
||||
} else {
|
||||
qCritical() << "ERROR EMPTY RESULT FROM 'GIT FETCH'";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCritical() << "ERROR" << customerRepository << "DOES NOT EXIST";
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool GitClient::gitFetchAndDiff() {
|
||||
if (gitFetch()) {
|
||||
QString gitCommand("git diff --compact-summary HEAD..FETCH_HEAD");
|
||||
Command c(gitCommand);
|
||||
return c.execute(m_workingDirectory);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GitClient::gitPull() {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
Command c("git pull");
|
||||
if (c.execute(m_customerRepository)) {
|
||||
qInfo() << "PULLED INTO" << m_customerRepository;
|
||||
return true;
|
||||
}
|
||||
qCritical() << "PULL INTO" << m_customerRepository << "FAILED";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<QStringList> GitClient::gitMerge() {
|
||||
Command c("git merge");
|
||||
if (c.execute(m_workingDirectory)) {
|
||||
QString s = c.getCommandResult();
|
||||
QStringList lst = Update::split(s, '\n');
|
||||
return lst;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QString GitClient::gitLastCommit(QString fileName) {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
QString const filePath
|
||||
= QDir::cleanPath(m_customerRepository + QDir::separator() + fileName);
|
||||
QString const gitCommand = QString("git log %1 | head -n 1").arg(fileName);
|
||||
Command c("bash");
|
||||
if (c.execute(m_customerRepository, QStringList() << "-c" << gitCommand)) {
|
||||
QString const r = c.getCommandResult();
|
||||
int const idx = r.indexOf("commit ");
|
||||
if (idx != -1) {
|
||||
return r.mid(idx + 8).trimmed();
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// get the blob of the file(name) passed as $1
|
||||
// note: this can be used for any file in the filesystem
|
||||
QString GitClient::gitBlob(QString fileName) {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
QString const filePath
|
||||
= QDir::cleanPath(m_customerRepository + QDir::separator() + fileName);
|
||||
QString const gitCommand = QString("git hash-object %1").arg(fileName);
|
||||
Command c(gitCommand);
|
||||
if (c.execute(m_customerRepository)) {
|
||||
return c.getCommandResult();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QString GitClient::gitCommitForBlob(QString blob) {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
QString const gitCommand
|
||||
= QString("git whatchanged --all --find-object=%1 | head -n 1").arg(blob);
|
||||
Command c(gitCommand);
|
||||
if (c.execute(m_customerRepository)) {
|
||||
return c.getCommandResult();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool GitClient::gitIsFileTracked(QString fName) {
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
QString const gitCommand
|
||||
= QString("git ls-files --error-unmatch %1").arg(fName);
|
||||
Command c(gitCommand);
|
||||
return c.execute(m_customerRepository);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//get_commit_for_blob () {
|
||||
// # search for the blob in all commits for the file(name) $1
|
||||
// echo $(git log --all --pretty=format:%H -- $2 |
|
||||
// xargs -I{} bash -c "git ls-tree {} -- $2 |
|
||||
// grep -q $1 && echo -n {} && head -n 1")
|
||||
//}
|
62
git/git_client.h
Normal file
62
git/git_client.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef GIT_CLIENT_H_INCLUDED
|
||||
#define GIT_CLIENT_H_INCLUDED
|
||||
|
||||
#include <QObject>
|
||||
#include <optional>
|
||||
|
||||
#include "process/command.h"
|
||||
|
||||
class Worker;
|
||||
class GitClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Worker *m_worker;
|
||||
QString const m_repositoryPath;
|
||||
QString const m_customerId;
|
||||
QString const m_workingDirectory;
|
||||
QString const m_branchName;
|
||||
QString const m_customerRepository;
|
||||
|
||||
bool copyGitConfigFromMaster();
|
||||
|
||||
public:
|
||||
explicit GitClient(QString const &repositoryPath,
|
||||
QString const &customerId,
|
||||
QString const &workingDirectory = QCoreApplication::applicationDirPath(),
|
||||
QString const &branchName = "master",
|
||||
QObject *parent = 0);
|
||||
|
||||
bool gitCloneCustomerRepository();
|
||||
bool gitCheckoutBranch();
|
||||
|
||||
QString const workingDirectory() const { return m_workingDirectory; }
|
||||
QString workingDirectory() { return m_workingDirectory; }
|
||||
|
||||
QString const branchName() const { return m_branchName; }
|
||||
QString branchName() { return m_branchName; }
|
||||
|
||||
QString repositoryPath() { return m_repositoryPath; }
|
||||
QString const repositoryPath() const { return m_repositoryPath; }
|
||||
|
||||
bool gitCloneAndCheckoutBranch();
|
||||
|
||||
std::optional<QString> gitFetch();
|
||||
bool gitFetchAndDiff();
|
||||
bool gitPull();
|
||||
std::optional<QStringList> gitDiff(QString const &commit);
|
||||
std::optional<QStringList> gitMerge();
|
||||
|
||||
QString gitLastCommit(QString fileName);
|
||||
QString gitBlob(QString fileName);
|
||||
QString gitCommitForBlob(QString blob);
|
||||
bool gitIsFileTracked(QString file2name);
|
||||
|
||||
signals:
|
||||
void ismasUpdatesAvailable();
|
||||
|
||||
public slots:
|
||||
void onIsmasUpdatesAvailable();
|
||||
|
||||
};
|
||||
|
||||
#endif // GIT_CLIENT_H_INCLUDED
|
212
ismas/ismas_client.cpp
Normal file
212
ismas/ismas_client.cpp
Normal file
@ -0,0 +1,212 @@
|
||||
#include "ismas/ismas_client.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#if 0
|
||||
# $1: EVENT: U0001 update finished: 100%
|
||||
# U0002 reset TRG
|
||||
# U0003 error
|
||||
# U0010 for update process
|
||||
# $2: PERCENT : "only for ISMAS: 0-100%",
|
||||
# $3: RESULTCODE : "only for ISMAS",
|
||||
# 0: Success
|
||||
# 1: no Update nessesary
|
||||
# 2: Backup failed
|
||||
# 3: Package error/ Wrong package
|
||||
# 4: Install Error
|
||||
# $4: STEP : "running step (only for us): update_psa...",
|
||||
# $5: STEP_RESULT : "error and result text",
|
||||
# $6: VERSION : "opkg and conf info; what will be updated"
|
||||
#
|
||||
#endif
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
QString IsmasClient::updateNewsToIsmas(char const *event,
|
||||
int percent,
|
||||
int resultCode,
|
||||
char const *step,
|
||||
char const *step_result,
|
||||
char const *version) {
|
||||
char buf[1024];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
QString const ts = QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
snprintf(buf, sizeof(buf)-1,
|
||||
"{"
|
||||
"\"REASON\":\"SW_UP\","
|
||||
"\"TIMESTAMP\":\"%s\","
|
||||
"\"EVENT_ID\":\"0\","
|
||||
"\"EVENT\":\"%s\","
|
||||
"\"EVENTSTATE\":1,"
|
||||
"\"PARAMETER\": {"
|
||||
"\"PERCENT\" : %d,"
|
||||
"\"RESULTCODE\" : %d,"
|
||||
"\"STEP\" : \"%s\","
|
||||
"\"STEP_RESULT\" : \"%s\","
|
||||
"\"VERSION\" : \"%s\""
|
||||
"}"
|
||||
"}", ts.toStdString().c_str(), event, percent, resultCode,
|
||||
step, step_result, version);
|
||||
return buf;
|
||||
}
|
||||
|
||||
QString IsmasClient::updateOfPSASendVersion(QString const &tariffVersion,
|
||||
QString const &tariffProject,
|
||||
int tariffZone,
|
||||
QString const &tariffInfo,
|
||||
QString const &tariffLoadTime,
|
||||
QString const &linuxVersion,
|
||||
QString const &cpuSerial,
|
||||
QString const &deviceControllerVersion,
|
||||
QString const &deviceControllerGitBlob,
|
||||
QString const &deviceControllerGitLastCommit,
|
||||
QString const &raucVersion,
|
||||
QString const &opkgVersion,
|
||||
QString const &atbQTVersion,
|
||||
QString const &atbQTGitDescribe,
|
||||
QString const &deviceControllerPluginVersion,
|
||||
QString const &ingenicoISelfCCPluginVersion,
|
||||
QString const &mobilisisCalculatePricePluginVersion,
|
||||
QString const &mobilisisCalculatePriceConfigUiVersion,
|
||||
QString const &prmCalculatePricePluginVersion,
|
||||
QString const &prmCalculatePriceConfigUiPluginVersion,
|
||||
QString const &tcpZVTPluginVersion) {
|
||||
char buf[4096];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
QString const ts = QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
QString sendVersionHash;
|
||||
|
||||
// local data="#M=APISM#C=CMD_SENDVERSION#J=
|
||||
snprintf(buf, sizeof(buf)-1,
|
||||
"{"
|
||||
"\"VERSION_INFO\" : {"
|
||||
"\"CREATED\":\"%s\","
|
||||
"\"HASH\":\"%s\""
|
||||
"},"
|
||||
"\"TARIFF\" : {"
|
||||
"\"VERSION\" : \"%s\","
|
||||
"\"PROJECT\" : \"%s\","
|
||||
"\"ZONE\" : %d,"
|
||||
"\"INFO\" : \"%s\","
|
||||
"\"LOADED\" : \"%s\""
|
||||
"},"
|
||||
"\"HARDWARE\" : {"
|
||||
"\"DEVICES\" : [\"PTU5\", \"DC\", \"PRINTER\", \"BNA\"]"
|
||||
"},"
|
||||
"\"OS\" : {"
|
||||
"\"Linux\": \"%s\""
|
||||
"},"
|
||||
"\"CONFIG\" : {"
|
||||
"\"PTU5\" : {"
|
||||
"\"CPU_SERIAL\" : \"%s\""
|
||||
"},"
|
||||
"\"DC\" : {"
|
||||
"\"VERSION\" : \"%s\","
|
||||
"\"GITBLOB\" : \"%s\","
|
||||
"\"GITLASTCOMMIT\" : \"%s\""
|
||||
"},"
|
||||
"\"PRINTER\" : {"
|
||||
"},"
|
||||
"\"BNA\" : {"
|
||||
"}"
|
||||
"},"
|
||||
"\"SOFTWARE\": {"
|
||||
"\"RAUC\" : \"%s\","
|
||||
"\"OPKG\" : \"%s\","
|
||||
"\"ATBQT\" : {"
|
||||
"\"VERSION\" : \"%s\","
|
||||
"\"GIT_DESCRIBE\" : \"%s\""
|
||||
"}"
|
||||
"},"
|
||||
"\"PLUGINS\" : {"
|
||||
"\"libATBDeviceControllerPlugin.so\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"},"
|
||||
"\"libIngenicoISelf_CCPlugin.so\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"},"
|
||||
"\"libMOBILISIS_CalculatePricePlugin.so\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"},"
|
||||
"\"libMOBILISIS_CalculatePricePlugin_ConfigUi.so\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"},"
|
||||
"\"libPRM_CalculatePricePlugin.so\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"},"
|
||||
"\"libPRM_CalculatePricePlugin_ConfigUi.so\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"},"
|
||||
"\"libTCP_ZVT_CCPlugin.so\" : {"
|
||||
"\"VERSION\" : \"%s\""
|
||||
"}"
|
||||
"}"
|
||||
"}",
|
||||
ts.toStdString().c_str(),
|
||||
sendVersionHash.toStdString().c_str(),
|
||||
|
||||
tariffVersion.toStdString().c_str(),
|
||||
tariffProject.toStdString().c_str(),
|
||||
tariffZone,
|
||||
tariffInfo.toStdString().c_str(),
|
||||
tariffLoadTime.toStdString().c_str(),
|
||||
|
||||
linuxVersion.toStdString().c_str(),
|
||||
|
||||
cpuSerial.toStdString().c_str(),
|
||||
|
||||
deviceControllerVersion.toStdString().c_str(),
|
||||
deviceControllerGitBlob.toStdString().c_str(),
|
||||
deviceControllerGitLastCommit.toStdString().c_str(),
|
||||
|
||||
raucVersion.toStdString().c_str(),
|
||||
opkgVersion.toStdString().c_str(),
|
||||
atbQTVersion.toStdString().c_str(),
|
||||
atbQTGitDescribe.toStdString().c_str(),
|
||||
|
||||
deviceControllerPluginVersion.toStdString().c_str(),
|
||||
ingenicoISelfCCPluginVersion.toStdString().c_str(),
|
||||
mobilisisCalculatePricePluginVersion.toStdString().c_str(),
|
||||
mobilisisCalculatePriceConfigUiVersion.toStdString().c_str(),
|
||||
prmCalculatePricePluginVersion.toStdString().c_str(),
|
||||
prmCalculatePriceConfigUiPluginVersion.toStdString().c_str(),
|
||||
tcpZVTPluginVersion.toStdString().c_str());
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
QString IsmasClient::updateOfPSAActivated() {
|
||||
return updateNewsToIsmas("U0010",
|
||||
1,
|
||||
0,
|
||||
"activated",
|
||||
"detected WAIT state",
|
||||
"1.0.0");
|
||||
}
|
||||
|
||||
QString IsmasClient::updateOfPSASucceeded() {
|
||||
return updateNewsToIsmas("U0001",
|
||||
100,
|
||||
0,
|
||||
"update_succeeded",
|
||||
"",
|
||||
"1.0.0");
|
||||
}
|
||||
|
||||
QString IsmasClient::setUpdatesAvailable() {
|
||||
return updateNewsToIsmas("U0099",
|
||||
10,
|
||||
0,
|
||||
"set_updates_available",
|
||||
"",
|
||||
"");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool checkForAvailableUpdates();
|
46
ismas/ismas_client.h
Normal file
46
ismas/ismas_client.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef ISMAS_CLIENT_H_INCLUDED
|
||||
#define ISMAS_CLIENT_H_INCLUDED
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class IsmasClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QString updateNewsToIsmas(char const *event,
|
||||
int percent,
|
||||
int resultCode,
|
||||
char const *step,
|
||||
char const *step_result,
|
||||
char const *version);
|
||||
|
||||
QString updateOfPSAActivated();
|
||||
QString updateOfPSASucceeded();
|
||||
QString updateOfPSASendVersion(QString const &tariffVersion,
|
||||
QString const &tariffProject,
|
||||
int tariffZone,
|
||||
QString const &tariffInfo,
|
||||
QString const &tariffLoadTime,
|
||||
QString const &linuxVersion,
|
||||
QString const &cpuSerial,
|
||||
QString const &deviceControllerVersion,
|
||||
QString const &deviceControllerGitBlob,
|
||||
QString const &deviceControllerGitLastCommit,
|
||||
QString const &raucVersion,
|
||||
QString const &opkgVersion,
|
||||
QString const &atbQTVersion,
|
||||
QString const &atbQTGitDescribe,
|
||||
QString const &deviceControllerPluginVersion,
|
||||
QString const &ingenicoISelfCCPluginVersion,
|
||||
QString const &mobilisisCalculatePricePluginVersion,
|
||||
QString const &mobilisisCalculatePriceConfigUiVersion,
|
||||
QString const &prmCalculatePricePluginVersion,
|
||||
QString const &prmCalculatePriceConfigUiPluginVersion,
|
||||
QString const &tcpZVTPluginVersion);
|
||||
|
||||
QString setUpdatesAvailable();
|
||||
bool checkForAvailableUpdates();
|
||||
};
|
||||
|
||||
#endif // ISMAS_CLIENT_H_INCLUDED
|
78
main.cpp
78
main.cpp
@ -12,7 +12,6 @@
|
||||
#include "plugins/interfaces.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <QSharedMemory>
|
||||
#include <QRunnable>
|
||||
@ -23,10 +22,13 @@
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "update.h"
|
||||
#include "git/git_client.h"
|
||||
#include "ismas/ismas_client.h"
|
||||
#include "apism/apism_client.h"
|
||||
#include "worker_thread.h"
|
||||
#include "worker.h"
|
||||
|
||||
#include <thread>
|
||||
#include <QThread>
|
||||
|
||||
#ifdef PTU5
|
||||
#define SERIAL_PORT "ttymxc2"
|
||||
@ -34,31 +36,21 @@
|
||||
#define SERIAL_PORT "ttyUSB0"
|
||||
#endif
|
||||
|
||||
class hwinf;
|
||||
static void doWork(hwinf *hw, QString update_ctrl_file,
|
||||
QString workingDir, bool maintenanceMode) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||
Update update(hw, update_ctrl_file, workingDir, maintenanceMode);
|
||||
update.doUpdate();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
// argv[1]: file to send to dc
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
QByteArray const value = qgetenv("XDG_RUNTIME_DIR");
|
||||
if (value.size() == 0) {
|
||||
qputenv("XDG_RUNTIME_DIR", "/run/user/0");
|
||||
QByteArray const value = qgetenv("LC_ALL");
|
||||
if (value != "C") {
|
||||
qputenv("LC_ALL", "C");
|
||||
}
|
||||
// qputenv("XDG_RUNTIME_DIR", "/run/user/0");
|
||||
|
||||
QApplication a(argc, argv);
|
||||
QApplication::setApplicationName("ATBUpdateTool");
|
||||
QApplication::setApplicationVersion("1.0");
|
||||
QApplication::setApplicationVersion(APP_VERSION);
|
||||
|
||||
if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
|
||||
atbInstallMessageHandler(atbDebugOutput);
|
||||
setDebugLevel(QtMsgType::QtDebugMsg);
|
||||
setDebugLevel(QtMsgType::QtInfoMsg);
|
||||
//setDebugLevel(QtMsgType::QtDebugMsg);
|
||||
}
|
||||
|
||||
@ -88,10 +80,24 @@ int main(int argc, char *argv[]) {
|
||||
workingDirectoryOption.setDefaultValue(workingDirectoryDefault);
|
||||
parser.addOption(workingDirectoryOption);
|
||||
|
||||
QCommandLineOption maintenanceOption("m",
|
||||
QCommandLineOption maintenanceOption(QStringList() << "m" << "maintenance",
|
||||
QCoreApplication::translate("main", "Maintenance mode for underlying script"));
|
||||
parser.addOption(maintenanceOption);
|
||||
|
||||
// test-mode: edit the file update_log.csv and execute the commands
|
||||
// contained in it. Do not call the update-script.
|
||||
QCommandLineOption testOption(QStringList() << "t" << "test",
|
||||
QCoreApplication::translate("main", "Test mode for ATBUpdateTool"));
|
||||
parser.addOption(testOption);
|
||||
|
||||
QCommandLineOption execScriptOption(QStringList() << "e" << "execute-script-only",
|
||||
QCoreApplication::translate("main", "ATBUpdateTool executes update-script only. No download of any files."));
|
||||
parser.addOption(execScriptOption);
|
||||
|
||||
QCommandLineOption dryRunOption(QStringList() << "d" << "dry-run",
|
||||
QCoreApplication::translate("main", "Start ATBUpdateTool in dry-run-mode. No actual actions."));
|
||||
parser.addOption(dryRunOption);
|
||||
|
||||
// TODO:
|
||||
// add some additional parameters
|
||||
// --dry-run
|
||||
@ -106,6 +112,9 @@ int main(int argc, char *argv[]) {
|
||||
QString plugInName = parser.value(pluginNameOption);
|
||||
QString workingDir = parser.value(workingDirectoryOption);
|
||||
bool maintenanceMode = parser.isSet(maintenanceOption);
|
||||
bool testMode = parser.isSet(testOption);
|
||||
bool executeScriptOnly = parser.isSet(execScriptOption);
|
||||
bool dryRun = parser.isSet(dryRunOption);
|
||||
QString const rtPath = QCoreApplication::applicationDirPath();
|
||||
|
||||
if (plugInDir == pluginDefault) {
|
||||
@ -116,11 +125,15 @@ int main(int argc, char *argv[]) {
|
||||
<< "does not exists, but has to contain dc-library";
|
||||
exit(-1);
|
||||
}
|
||||
qInfo() << "pwd" << "=" << rtPath;
|
||||
qInfo() << "plugInDir" << "=" << plugInDir;
|
||||
qInfo() << "plugInName" << "=" << plugInName;
|
||||
qInfo() << "workingDir" << "=" << workingDir;
|
||||
qInfo() << "maintenanceMode" << "=" << maintenanceMode;
|
||||
|
||||
qInfo() << "pwd ..............." << rtPath;
|
||||
qInfo() << "plugInDir ........." << plugInDir;
|
||||
qInfo() << "plugInName ........" << plugInName;
|
||||
qInfo() << "workingDir ........" << workingDir;
|
||||
qInfo() << "maintenanceMode ..." << maintenanceMode;
|
||||
qInfo() << "testMode .........." << testMode;
|
||||
qInfo() << "execScriptOnly ...." << executeScriptOnly;
|
||||
qInfo() << "dryRun ............" << dryRun;
|
||||
|
||||
// before loading the library, delete all possible shared memory segments
|
||||
#if defined Q_OS_LINUX || defined Q_OS_UNIX
|
||||
@ -130,13 +143,18 @@ int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
|
||||
hwinf *hw = Update::loadDCPlugin(QDir(plugInDir), plugInName);
|
||||
hw->dc_autoRequest(false);
|
||||
// hw->dc_autoRequest(false);
|
||||
|
||||
QString const update_ctrl_file = "/opt/app/tools/atbupdate/update_log.csv";
|
||||
std::thread t(doWork, hw, update_ctrl_file, workingDir, maintenanceMode);
|
||||
Worker worker(hw, update_ctrl_file,
|
||||
"https://git.mimbach49.de/GerhardHoffmann/customer_999.git",
|
||||
"customer_999",
|
||||
"zg1/zone1",
|
||||
workingDir,
|
||||
maintenanceMode,
|
||||
testMode,
|
||||
executeScriptOnly,
|
||||
dryRun);
|
||||
|
||||
int ret = a.exec();
|
||||
t.join();
|
||||
|
||||
return ret;
|
||||
return a.exec();
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include <QDateTime>
|
||||
#include <cstring>
|
||||
#include <QString>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageLogContext>
|
||||
|
||||
#define OUTPUT_LEN (512)
|
||||
|
||||
@ -42,51 +45,43 @@ QtMessageHandler atbInstallMessageHandler(QtMessageHandler handler) {
|
||||
///
|
||||
#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
|
||||
static constexpr const char *format = "hh:mm:ss";
|
||||
// static constexpr const char *format = "dd.MM.yyyy hh:mm:ss";
|
||||
QByteArray localMsg = msg.toLocal8Bit();
|
||||
const char *file = context.file ? context.file : "";
|
||||
const char *function = context.function ? context.function : "";
|
||||
const char *p = std::strstr(function, "::");
|
||||
if (p) {
|
||||
function = p + 2;
|
||||
}
|
||||
char const* output = std::strrchr(file, '/');
|
||||
if (output) {
|
||||
file = output + 1;
|
||||
}
|
||||
qint64 const currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch();
|
||||
int const fractional_part = currentMSecsSinceEpoch % 1000;
|
||||
QString fileName(context.file ? context.file : "N/A");
|
||||
QString function(context.function ? context.function : "N/A");
|
||||
char buf[OUTPUT_LEN]{};
|
||||
memset(buf, 0x00, sizeof(buf));
|
||||
QDateTime const datetime = QDateTime::fromMSecsSinceEpoch(currentMSecsSinceEpoch);
|
||||
QString const datetime = QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
switch (type) {
|
||||
case QtDebugMsg: {
|
||||
if (debugLevel == QtDebugMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d DEBG %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
snprintf(buf, sizeof(buf)-1, "%s DEBG [%s:%s:%04u] %s",
|
||||
datetime.toStdString().c_str(),
|
||||
function.toStdString().c_str(),
|
||||
fileName.toStdString().c_str(),
|
||||
context.line,
|
||||
localMsg.constData());
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
}
|
||||
} break;
|
||||
case QtInfoMsg: {
|
||||
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d INFO %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
snprintf(buf, sizeof(buf)-1, "%s DEBG [%s:%s:%04u] %s",
|
||||
datetime.toStdString().c_str(),
|
||||
function.toStdString().c_str(),
|
||||
fileName.toStdString().c_str(),
|
||||
context.line,
|
||||
localMsg.constData());
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
}
|
||||
} break;
|
||||
case QtWarningMsg: {
|
||||
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg || debugLevel == QtWarningMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d WARN %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
snprintf(buf, sizeof(buf)-1, "%s DEBG [%s:%s:%04u] %s",
|
||||
datetime.toStdString().c_str(),
|
||||
function.toStdString().c_str(),
|
||||
fileName.toStdString().c_str(),
|
||||
context.line,
|
||||
localMsg.constData());
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
}
|
||||
@ -94,10 +89,11 @@ void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QSt
|
||||
case QtCriticalMsg: {
|
||||
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg
|
||||
|| debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d CRIT %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
snprintf(buf, sizeof(buf)-1, "%s DEBG [%s:%s:%04u] %s",
|
||||
datetime.toStdString().c_str(),
|
||||
function.toStdString().c_str(),
|
||||
fileName.toStdString().c_str(),
|
||||
context.line,
|
||||
localMsg.constData());
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
}
|
||||
@ -106,18 +102,18 @@ void atbDebugOutput(QtMsgType type, const QMessageLogContext &context, const QSt
|
||||
if (debugLevel == QtInfoMsg || debugLevel == QtDebugMsg
|
||||
|| debugLevel == QtWarningMsg || debugLevel == QtCriticalMsg
|
||||
|| debugLevel == QtFatalMsg) {
|
||||
snprintf(buf, sizeof(buf)-1, "%30.30s (%20.20s:%04u) %s.%03d FATAL %s\n",
|
||||
function, file, context.line,
|
||||
datetime.time().toString(format).toStdString().c_str(),
|
||||
fractional_part,
|
||||
snprintf(buf, sizeof(buf)-1, "%s DEBG [%s:%s:%04u] %s",
|
||||
datetime.toStdString().c_str(),
|
||||
function.toStdString().c_str(),
|
||||
fileName.toStdString().c_str(),
|
||||
context.line,
|
||||
localMsg.constData());
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
fprintf(stderr, "%*.*s.%03d No ErrorLevel defined! %s\n", OUTPUT_LEN, OUTPUT_LEN,
|
||||
datetime.time().toString(format).toStdString().c_str(), fractional_part,
|
||||
msg.toStdString().c_str());
|
||||
fprintf(stderr, "%s No ErrorLevel defined! %s\n",
|
||||
datetime.toStdString().c_str(), msg.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
79
process/command.cpp
Normal file
79
process/command.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include <QRegularExpression>
|
||||
|
||||
Command::Command(QString const &command, int start_timeout, int finish_timeout)
|
||||
: m_command(command.trimmed())
|
||||
, m_commandResult("")
|
||||
, m_waitForStartTimeout(start_timeout)
|
||||
, m_waitForFinishTimeout(finish_timeout) {
|
||||
}
|
||||
|
||||
QString Command::getCommandResult() const {
|
||||
return m_commandResult;
|
||||
}
|
||||
|
||||
void Command::readyReadStandardOutput() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
m_commandResult += p->readAllStandardOutput();
|
||||
// qCritical() << m_commandResult;
|
||||
}
|
||||
|
||||
void Command::readyReadStandardError() {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
QByteArray buf = p->readAllStandardError();
|
||||
qCritical() << buf;
|
||||
}
|
||||
|
||||
void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
|
||||
QProcess *p = (QProcess *)sender();
|
||||
// read all remaining data sent to the process, just in case
|
||||
QString d = p->readAllStandardOutput();
|
||||
if (!d.isEmpty()) {
|
||||
m_commandResult += d;
|
||||
}
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput()));
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
|
||||
}
|
||||
|
||||
bool Command::execute(QString workingDirectory, QStringList args) {
|
||||
QScopedPointer<QProcess> p(new QProcess(this));
|
||||
p->setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
connect(&(*p), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()));
|
||||
connect(&(*p), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()));
|
||||
|
||||
qCritical() << "START COMMAND" << m_command << "IN" << workingDirectory;
|
||||
|
||||
p->setWorkingDirectory(workingDirectory);
|
||||
if (!args.isEmpty()) {
|
||||
p->start(m_command, args);
|
||||
} else {
|
||||
p->start(m_command);
|
||||
}
|
||||
|
||||
if (p->waitForStarted(m_waitForStartTimeout)) {
|
||||
if (p->state() == QProcess::ProcessState::Running) {
|
||||
if (p->waitForFinished(m_waitForFinishTimeout)) {
|
||||
if (p->exitStatus() == QProcess::NormalExit) {
|
||||
qInfo() << "EXECUTED" << m_command
|
||||
<< "with code" << p->exitCode();
|
||||
// qInfo() << "RESULT" << m_commandResult;
|
||||
return true;
|
||||
} else {
|
||||
qCritical() << "PROCESS" << m_command << "CRASHED with code"
|
||||
<< p->exitCode();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "PROCESS" << m_command << "DID NOT FINISH";
|
||||
}
|
||||
} else {
|
||||
qCritical() << "WRONG PROCESS STATE" << p->state();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "PROCESS" << m_command << "TIMEOUT AT START";
|
||||
}
|
||||
return false;
|
||||
}
|
33
process/command.h
Normal file
33
process/command.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef COMMAND_H_INCLUDED
|
||||
#define COMMAND_H_INCLUDED
|
||||
#endif // COMMAND_H_INCLUDED
|
||||
|
||||
#include <QObject>
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QProcess>
|
||||
|
||||
|
||||
class Command : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
QString m_command;
|
||||
QString m_commandResult;
|
||||
int m_waitForStartTimeout;
|
||||
int m_waitForFinishTimeout;
|
||||
|
||||
public:
|
||||
explicit Command(QString const &command,
|
||||
int start_timeout = 100000,
|
||||
int finish_timeout = 100000);
|
||||
|
||||
QString getCommandResult() const;
|
||||
|
||||
bool execute(QString workingDirectory, QStringList args = QStringList());
|
||||
|
||||
private slots:
|
||||
void readyReadStandardOutput();
|
||||
void readyReadStandardError();
|
||||
void finished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
};
|
287
update.cpp
287
update.cpp
@ -8,6 +8,10 @@
|
||||
#include <QTextStream>
|
||||
#include <QRegularExpression>
|
||||
|
||||
//#include <iostream>
|
||||
//#include <fstream>
|
||||
//#include <ctime>
|
||||
|
||||
#include "plugins/interfaces.h"
|
||||
|
||||
#include <QSharedMemory>
|
||||
@ -24,8 +28,8 @@
|
||||
#define COLUMN_RESULT (3)
|
||||
|
||||
#define UPDATE_OPKG (1)
|
||||
#define UPDATE_DC (0)
|
||||
#define UPDATE_PRINTER_TEMPLATES (0)
|
||||
#define UPDATE_DC (1)
|
||||
#define UPDATE_PRINTER_TEMPLATES (1)
|
||||
#define UPDATE_CASH_TEMPLATE (0)
|
||||
#define UPDATE_CONF_TEMPLATE (0)
|
||||
#define UPDATE_DEVICE_TEMPLATE (0)
|
||||
@ -77,8 +81,14 @@ hwinf *Update::loadDCPlugin(QDir const &plugInDir, QString const &fname) {
|
||||
|
||||
Update::Update(hwinf *hw,
|
||||
QString update_ctrl_file,
|
||||
QString repositoryPath,
|
||||
QString customerId,
|
||||
QString branchName,
|
||||
QString workingDir,
|
||||
bool maintenanceMode,
|
||||
bool testMode,
|
||||
bool executeScriptOnly,
|
||||
bool dryRun,
|
||||
QObject *parent,
|
||||
char const *serialInterface,
|
||||
char const *baudrate)
|
||||
@ -88,39 +98,53 @@ Update::Update(hwinf *hw,
|
||||
, m_baudrate(baudrate)
|
||||
, m_update_ctrl_file(update_ctrl_file)
|
||||
, m_update_ctrl_file_copy(update_ctrl_file + ".copy")
|
||||
, m_repositoryPath(repositoryPath)
|
||||
, m_customerId(customerId)
|
||||
, m_branchName(branchName)
|
||||
, m_workingDir(workingDir)
|
||||
, m_maintenanceMode(maintenanceMode)
|
||||
, m_testMode(testMode)
|
||||
, m_executeScriptOnly(executeScriptOnly)
|
||||
, m_dryRun(dryRun)
|
||||
//, m_apismClient(nullptr, nullptr, nullptr)
|
||||
, m_init(true) {
|
||||
|
||||
// make sure the files are empty
|
||||
if (m_update_ctrl_file.exists()) {
|
||||
if (m_update_ctrl_file.open(QIODevice::ReadWrite |
|
||||
QIODevice::Truncate |
|
||||
QIODevice::Text)) {
|
||||
m_update_ctrl_file.close();
|
||||
// m_apismClient.sendSelfTest();
|
||||
|
||||
if (!m_testMode) {
|
||||
// make sure the files are empty
|
||||
if (m_update_ctrl_file.exists()) {
|
||||
if (m_update_ctrl_file.open(QIODevice::ReadWrite |
|
||||
QIODevice::Truncate |
|
||||
QIODevice::Text)) {
|
||||
m_update_ctrl_file.close();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "Update-file" << m_update_ctrl_file.fileName()
|
||||
<< "does not exist";
|
||||
m_init = false;
|
||||
}
|
||||
} else {
|
||||
qCritical() << "Update-file" << m_update_ctrl_file.fileName()
|
||||
<< "does not exist";
|
||||
m_init = false;
|
||||
}
|
||||
if (m_update_ctrl_file_copy.exists()) {
|
||||
if (m_update_ctrl_file_copy.open(QIODevice::ReadWrite |
|
||||
QIODevice::Truncate |
|
||||
QIODevice::Text)) {
|
||||
m_update_ctrl_file_copy.close();
|
||||
if (m_update_ctrl_file_copy.exists()) {
|
||||
if (m_update_ctrl_file_copy.open(QIODevice::ReadWrite |
|
||||
QIODevice::Truncate |
|
||||
QIODevice::Text)) {
|
||||
m_update_ctrl_file_copy.close();
|
||||
}
|
||||
} else {
|
||||
qCritical() << "Update-file-copy" << m_update_ctrl_file_copy.fileName()
|
||||
<< "does not exist";
|
||||
m_init = false;
|
||||
}
|
||||
} else {
|
||||
qCritical() << "Update-file-copy" << m_update_ctrl_file_copy.fileName()
|
||||
<< "does not exist";
|
||||
m_init = false;
|
||||
}
|
||||
|
||||
// execute update_psa-script
|
||||
if (m_init) {
|
||||
if ((m_init = execUpdateScript()) == false) {
|
||||
qCritical() << "UPDATE_SCRIPT FAILED";
|
||||
} else {
|
||||
if (!m_testMode) {
|
||||
if ((m_init = execUpdateScript()) == false) {
|
||||
qCritical() << "UPDATE_SCRIPT FAILED";
|
||||
}
|
||||
}
|
||||
if (m_init) {
|
||||
if (!m_update_ctrl_file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||
qCritical() << "CAN NOT OPEN" << m_update_ctrl_file.fileName();
|
||||
m_init = false;
|
||||
@ -202,10 +226,10 @@ Update::DownloadResult Update::sendNextAddress(int bNum) const {
|
||||
int noAnswerCount = 0;
|
||||
int errorCount = 0;
|
||||
if ( bNum==0 || bNum==1024 || bNum==2048 || bNum==3072 || bNum==4096 ) {
|
||||
qDebug() << "addr-block" << bNum << "...";
|
||||
// qDebug() << "addr-block" << bNum << "...";
|
||||
while (noAnswerCount <= 250) {
|
||||
m_hw->bl_sendAddress(bNum);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
QThread::msleep(100);
|
||||
DownloadResult const res = sendStatus(m_hw->bl_wasSendingAddOK());
|
||||
if (res != DownloadResult::NOP) {
|
||||
if (res == DownloadResult::ERROR) {
|
||||
@ -214,7 +238,7 @@ Update::DownloadResult Update::sendNextAddress(int bNum) const {
|
||||
return res;
|
||||
}
|
||||
} else { // res == DownloadResult::OK
|
||||
qInfo() << "addr-block" << bNum << "...OK";
|
||||
// qInfo() << "addr-block" << bNum << "...OK";
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
@ -238,16 +262,12 @@ Update::DownloadResult Update::sendNextDataBlock(QByteArray const &binary,
|
||||
memcpy(local, binary.constData() + bAddr, 64);
|
||||
local[64] = local[65] = 0x00;
|
||||
|
||||
//for (int i=0; i<4; ++i) {
|
||||
// printf("%04d ", bNum);
|
||||
// for (int j=0; j < 16; ++j) {
|
||||
// printf("%02x ", local[i*16 + j]);
|
||||
// } printf("\n");
|
||||
//}
|
||||
// QByteArray b((const char *)(&local[0]), 64);
|
||||
// qCritical() << "SNDB" << bNum << b.size() << b.toHex();
|
||||
|
||||
while (noAnswerCount <= 250) {
|
||||
m_hw->bl_sendDataBlock(64, local);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
QThread::msleep(10);
|
||||
DownloadResult const res = sendStatus(m_hw->bl_wasSendingDataOK());
|
||||
if (res != DownloadResult::NOP) {
|
||||
if (res == DownloadResult::ERROR) {
|
||||
@ -256,7 +276,7 @@ Update::DownloadResult Update::sendNextDataBlock(QByteArray const &binary,
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
qInfo() << "data for block" << bNum << "OK";
|
||||
// qInfo() << "data for block" << bNum << "OK";
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
@ -270,39 +290,41 @@ Update::DownloadResult Update::sendNextDataBlock(QByteArray const &binary,
|
||||
Update::DownloadResult Update::dc_downloadBinary(QByteArray const &b) const {
|
||||
int const nBlocks = (((b.size())%64)==0) ? (b.size()/64) : (b.size()/64)+1;
|
||||
|
||||
qInfo() << "total number of bytes to send to dc" << b.size();
|
||||
// fill lst block of data to be sent with 0xFF
|
||||
QByteArray ba = b.leftJustified(nBlocks*64, (char)(0xFF));
|
||||
|
||||
qInfo() << "total number of bytes to send to dc" << ba.size();
|
||||
qInfo() << "total number of blocks to send to dc" << nBlocks;
|
||||
|
||||
int bNum = 0;
|
||||
DownloadResult res = DownloadResult::OK;
|
||||
fprintf(stderr, "\n64-byte block %04d ", bNum);
|
||||
while (res != DownloadResult::ERROR && bNum < nBlocks) {
|
||||
if ((res = sendNextAddress(bNum)) != DownloadResult::ERROR) {
|
||||
if ((res = sendNextDataBlock(b, bNum)) != DownloadResult::ERROR) {
|
||||
if ((res = sendNextDataBlock(ba, bNum)) != DownloadResult::ERROR) {
|
||||
bNum += 1;
|
||||
fprintf(stderr, ".");
|
||||
if ((bNum % 80) == 0) {
|
||||
fprintf(stderr, "\n64-byte block %04d ", bNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
qInfo() << "nBlocks" << nBlocks;
|
||||
//if (res != DownloadResult::ERROR) {
|
||||
// always send last block, even when there are no data !!!
|
||||
int const rest = b.size() % 64;
|
||||
int const offset = b.size() - rest;
|
||||
char const *startAddress = b.constData() + offset;
|
||||
fprintf(stderr, "\nlast 64-byte block %04d\n", bNum);
|
||||
|
||||
int const rest = ba.size() % 64;
|
||||
int const offset = ba.size() - rest;
|
||||
char const *startAddress = ba.constData() + offset;
|
||||
|
||||
uint8_t local[66];
|
||||
memset(local, 0x00, sizeof(local));
|
||||
if (rest > 0) {
|
||||
// SHOULD NEVER HAPPEN !!!
|
||||
uint8_t local[66];
|
||||
memset(local, 0xFF, sizeof(local));
|
||||
memcpy(local, startAddress, rest);
|
||||
qCritical() << "ERROR SEND REMAINING" << rest << "BYTES";
|
||||
m_hw->bl_sendDataBlock(64, local);
|
||||
}
|
||||
|
||||
//for (int i=0; i<4; ++i) {
|
||||
// printf("*** %04d ", bNum);
|
||||
// for (int j=0; j < 16; ++j) {
|
||||
// printf("%02x ", local[i*16 + j]);
|
||||
// } printf("\n");
|
||||
//}
|
||||
|
||||
// bl_sendLastBlock(local);
|
||||
m_hw->bl_sendLastBlock();
|
||||
qInfo() << "last result" << (int)sendStatus(m_hw->bl_wasSendingDataOK());
|
||||
return res;
|
||||
@ -313,11 +335,11 @@ bool Update::startBootloader() const {
|
||||
int nTry = 5;
|
||||
while (--nTry >= 0) {
|
||||
m_hw->bl_startBL();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
QThread::msleep(5000);
|
||||
m_hw->bl_checkBL();
|
||||
if (m_hw->bl_isUp()) {
|
||||
qInfo() << "starting bootloader...OK";
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
QThread::msleep(5000);
|
||||
return true;
|
||||
} else {
|
||||
qCritical() << "bootloader not up (" << nTry << ")";
|
||||
@ -332,7 +354,7 @@ bool Update::stopBootloader() const {
|
||||
int nTry = 5;
|
||||
while (--nTry >= 0) {
|
||||
m_hw->bl_stopBL();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
QThread::msleep(500);
|
||||
if (!m_hw->bl_isUp()) {
|
||||
qInfo() << "stopping bootloader...OK";
|
||||
return true;
|
||||
@ -354,14 +376,19 @@ bool Update::openSerial(int br, QString baudrate, QString comPort) const {
|
||||
}
|
||||
|
||||
void Update::closeSerial() const {
|
||||
qInfo() << "CLOSED SERIAL" << m_baudrate << m_serialInterface;
|
||||
m_hw->dc_closeSerial();
|
||||
}
|
||||
|
||||
bool Update::isSerialOpen() const {
|
||||
return m_hw->dc_isPortOpen();
|
||||
}
|
||||
|
||||
bool Update::resetDeviceController() const {
|
||||
qDebug() << "resetting device controller...";
|
||||
m_hw->bl_rebootDC();
|
||||
// wait maximally 3 seconds, before starting bootloader
|
||||
QThread::msleep(1500);
|
||||
QThread::sleep(1);
|
||||
qInfo() << "resetting device controller...OK";
|
||||
return true;
|
||||
}
|
||||
@ -459,15 +486,21 @@ bool Update::updateDC(QString bFile) const {
|
||||
return false;
|
||||
}
|
||||
if (!startBootloader()) {
|
||||
// even when start seems to fail, stopping the boot loader does not harm
|
||||
stopBootloader();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!downloadBinaryToDC(bFile)) {
|
||||
stopBootloader();
|
||||
qCritical() << "updating dc: " << bFile << "...FAILED";
|
||||
return false;
|
||||
}
|
||||
qInfo() << "updating dc: " << bFile << "...OK";
|
||||
|
||||
stopBootloader();
|
||||
//resetDeviceController();
|
||||
|
||||
QThread::sleep(3);
|
||||
return true;
|
||||
}
|
||||
@ -606,8 +639,15 @@ void Update::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
|
||||
disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
|
||||
}
|
||||
|
||||
// bool Update::executeProcess(QString const &cmd);
|
||||
|
||||
bool Update::doUpdate() {
|
||||
|
||||
//
|
||||
// ACHTUNG !!!
|
||||
//
|
||||
return true;
|
||||
|
||||
/*
|
||||
The file referred to by 'update_data' has the following structure for
|
||||
each line:
|
||||
@ -630,7 +670,12 @@ bool Update::doUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_executeScriptOnly) { // basically a test flag for executing only the
|
||||
return true; // update script.
|
||||
}
|
||||
|
||||
bool serialOpened = false;
|
||||
bool serialOpen = false;
|
||||
|
||||
QStringList linesToWorkOn = getLinesToWorkOn();
|
||||
if (linesToWorkOn.size() == 0) {
|
||||
@ -658,39 +703,75 @@ bool Update::doUpdate() {
|
||||
}
|
||||
QString const &request = lst[COLUMN_REQUEST];
|
||||
QString const &name = lst[COLUMN_NAME];
|
||||
|
||||
QTextStream out(&m_update_ctrl_file_copy);
|
||||
// QString const &datetime = lst[COLUMN_DATE_TIME];
|
||||
// QString const &result = lst[COLUMN_RESULT];
|
||||
qDebug() << "request=" << request << ", name=" << name;
|
||||
if (request.trimmed() == "DOWNLOAD") {
|
||||
if (!serialOpened) { // open serial code once
|
||||
if (!openSerial(baudrateMap.value(m_baudrate), m_baudrate, m_serialInterface)) {
|
||||
qCritical() << "CANNOT OPEN" << m_serialInterface << "(BAUDRATE="
|
||||
<< m_baudrate << ")";
|
||||
return false;
|
||||
if (!serialOpen) {
|
||||
if (!isSerialOpen()) { // open serial only if not already open
|
||||
if ((serialOpened = openSerial(baudrateMap.value(m_baudrate), m_baudrate, m_serialInterface)) == false) {
|
||||
qCritical() << "CANNOT OPEN" << m_serialInterface << "(BAUDRATE="
|
||||
<< m_baudrate << ")";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
serialOpen = true;
|
||||
qCritical() << "SERIAL OPEN" << m_serialInterface << "(BAUDRATE=" << m_baudrate << ")";
|
||||
}
|
||||
|
||||
serialOpened = true;
|
||||
|
||||
QString fwVersion = m_hw->dc_getSWversion();
|
||||
QString const hwVersion = m_hw->dc_getHWversion();
|
||||
|
||||
if (name.contains("dc2c", Qt::CaseInsensitive) &&
|
||||
name.endsWith(".bin", Qt::CaseInsensitive)) {
|
||||
qDebug() << "sending sw/hw-requests...";
|
||||
for (int i=0; i < 3; ++i) { // send explicit reuests to get
|
||||
// current SW/HW-versions
|
||||
m_hw->request_DC2_SWversion();
|
||||
m_hw->request_DC2_HWversion();
|
||||
QThread::sleep(1);
|
||||
}
|
||||
QString const hwVersion = m_hw->dc_getHWversion().toLower();
|
||||
QString const fwVersion = m_hw->dc_getSWversion().toLower();
|
||||
qInfo() << "current dc-hardware-version" << hwVersion;
|
||||
qInfo() << "current dc-firmware-version" << fwVersion;
|
||||
|
||||
m_hw->dc_autoRequest(false);// default: turn auto-request setting off
|
||||
QThread::sleep(3); // wait to be sure that there are no more
|
||||
// commands sent to dc-hardware
|
||||
qDebug() << "SET AUTO-REQUEST=FALSE";
|
||||
}
|
||||
if (name.contains("dc2c", Qt::CaseInsensitive) &&
|
||||
name.endsWith(".bin", Qt::CaseInsensitive)) {
|
||||
qInfo() << "downloading" << name.trimmed() << "to DC";
|
||||
res = true;
|
||||
QFile fn(name);
|
||||
QFileInfo linkTarget(fn.symLinkTarget());
|
||||
if (!linkTarget.exists()) { // check for broken link
|
||||
res = false;
|
||||
} else {
|
||||
if (false) {
|
||||
//if (fwVersion.startsWith(linkTarget.completeBaseName())) {
|
||||
// qCritical() << "current dc-firmware-version" << fwVersion
|
||||
// << "already installed";
|
||||
// res = false;
|
||||
} else {
|
||||
res = true;
|
||||
|
||||
qCritical() << "downloading" << name.trimmed() << "->"
|
||||
<< linkTarget.completeBaseName() << "to DC";
|
||||
#if UPDATE_DC == 1
|
||||
if ((res = updateBinary(name.toStdString().c_str())) == true) {
|
||||
qInfo() << "downloaded binary" << name;
|
||||
}
|
||||
m_hw->dc_autoRequest(false);// default: turn auto-request setting off
|
||||
QThread::sleep(1); // wait to be sure that there are no more
|
||||
// commands sent to dc-hardware
|
||||
qDebug() << "SET AUTO-REQUEST=FALSE";
|
||||
|
||||
if ((res = updateBinary(name.toStdString().c_str())) == true) {
|
||||
qCritical() << "downloaded binary" << name;
|
||||
}
|
||||
|
||||
m_hw->dc_autoRequest(true); // turn auto-request setting on
|
||||
qDebug() << "SET AUTO-REQUEST=TRUE";
|
||||
qDebug() << "WAIT 10 SECS TO RECEIVE RESPONSES...";
|
||||
|
||||
QThread::sleep(10); // wait to be sure that responses
|
||||
// have been received
|
||||
|
||||
qCritical() << "updated dc-hardware-version" << m_hw->dc_getHWversion();
|
||||
qCritical() << "updated dc-firmware-version" << m_hw->dc_getSWversion();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (name.contains("DC2C_print", Qt::CaseInsensitive)
|
||||
&& name.endsWith(".json", Qt::CaseInsensitive)) {
|
||||
res = true;
|
||||
@ -774,28 +855,19 @@ bool Update::doUpdate() {
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
char buf[128];
|
||||
memset(buf, 0x00, sizeof(buf));
|
||||
snprintf(buf, sizeof(buf)-1, "DONE, %*.*s, %*.*s, %*.*s\n",
|
||||
35, 35, name.toStdString().c_str(),
|
||||
20, 20, QDateTime::currentDateTime().toString(Qt::ISODate).toStdString().c_str(),
|
||||
10, 10, (res == true) ? "SUCCESS" : "ERROR");
|
||||
m_update_ctrl_file_copy.write(buf);
|
||||
|
||||
qInfo() << "write" << buf << "into file" << m_update_ctrl_file_copy;
|
||||
out << "DONE, " << name << ", "
|
||||
<< QDateTime::currentDateTime().toString(Qt::ISODate) << ", "
|
||||
<< ((res == true) ? "SUCCESS" : "ERROR") << "\n";
|
||||
out.flush();
|
||||
|
||||
} // for (it = openLines.cbegin(); it != openLines.end(); ++it) {
|
||||
|
||||
if (serialOpened) {
|
||||
m_hw->dc_autoRequest(true);
|
||||
qDebug() << "SET AUTO-REQUEST=TRUE";
|
||||
qInfo() << "current dc-hardware-version" << m_hw->dc_getHWversion();
|
||||
qInfo() << "current dc-firmware-version" << m_hw->dc_getSWversion();
|
||||
closeSerial();
|
||||
serialOpened = false;
|
||||
}
|
||||
m_hw->dc_autoRequest(true); // ALWAYS turn autoRequest ON
|
||||
qDebug() << "SET AUTO-REQUEST=TRUE";
|
||||
|
||||
return finishUpdate(linesToWorkOn.size() > 0);
|
||||
return true;
|
||||
|
||||
// return finishUpdate(linesToWorkOn.size() > 0);
|
||||
}
|
||||
|
||||
bool Update::finishUpdate(bool swapCtrlFiles) {
|
||||
@ -803,21 +875,12 @@ bool Update::finishUpdate(bool swapCtrlFiles) {
|
||||
m_update_ctrl_file.close();
|
||||
m_update_ctrl_file_copy.close();
|
||||
|
||||
QString const &fn = m_update_ctrl_file.fileName();
|
||||
QString const &fn_tmp = m_update_ctrl_file.fileName() + ".tmp";
|
||||
QString const &fn_copy = m_update_ctrl_file_copy.fileName();
|
||||
QFile tmp(fn_tmp);
|
||||
//std::ifstream source(m_update_ctrl_file_copy.fileName().toStdString().c_str(), std::ios::binary);
|
||||
//std::ofstream dest(m_update_ctrl_file.fileName().toStdString().c_str(), std::ios::binary);
|
||||
|
||||
if (tmp.exists()) {
|
||||
tmp.remove();
|
||||
}
|
||||
|
||||
if (m_update_ctrl_file.rename(fn_tmp)) {
|
||||
if (m_update_ctrl_file_copy.rename(fn)) {
|
||||
return m_update_ctrl_file.rename(fn_copy);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
//dest << source.rdbuf();
|
||||
//source.close();
|
||||
//dest.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
28
update.h
28
update.h
@ -9,6 +9,7 @@
|
||||
#include <QProcess>
|
||||
|
||||
#include "plugins/interfaces.h"
|
||||
#include "apism/apism_client.h"
|
||||
|
||||
#ifdef PTU5
|
||||
#define SERIAL_PORT "ttymxc2"
|
||||
@ -29,14 +30,20 @@ class Update : public QObject {
|
||||
char const *m_baudrate;
|
||||
QFile m_update_ctrl_file;
|
||||
QFile m_update_ctrl_file_copy;
|
||||
QString m_repositoryPath;
|
||||
QString m_customerId; // customer_281
|
||||
QString m_branchName;
|
||||
QString m_workingDir;
|
||||
bool m_maintenanceMode;
|
||||
bool m_testMode;
|
||||
bool m_executeScriptOnly;
|
||||
bool m_dryRun;
|
||||
//ApismClient m_apismClient;
|
||||
|
||||
bool m_init;
|
||||
|
||||
bool finishUpdate(bool finish);
|
||||
QStringList getLinesToWorkOn();
|
||||
QStringList split(QString line, QChar sep = ',');
|
||||
|
||||
bool execUpdateScript();
|
||||
|
||||
@ -45,18 +52,34 @@ public:
|
||||
enum class FileTypeJson {CONFIG=1, DEVICE=2, CASH=3, SERIAL=4, TIME=5, PRINTER=6};
|
||||
|
||||
static hwinf *loadDCPlugin(QDir const &plugInDir, QString const &fn);
|
||||
static QStringList split(QString line, QChar sep = ',');
|
||||
|
||||
|
||||
explicit Update(hwinf *hw,
|
||||
QString update_ctrl_file,
|
||||
QString repositoryPath,
|
||||
QString customerId,
|
||||
QString branchName,
|
||||
QString workingDir = ".",
|
||||
bool maintenanceMode = false,
|
||||
bool testMode = false,
|
||||
bool executeScriptOnly = false,
|
||||
bool dryRun = false,
|
||||
QObject *parent = nullptr,
|
||||
char const *serialInterface = SERIAL_PORT,
|
||||
char const *baudrate = "115200");
|
||||
virtual ~Update() override;
|
||||
bool doUpdate();
|
||||
|
||||
QString customerId() { return m_customerId; }
|
||||
QString const customerId() const { return m_customerId; }
|
||||
|
||||
QString branchName() { return m_branchName; }
|
||||
QString const branchName() const { return m_branchName; }
|
||||
|
||||
QString repositoryPath() { return m_repositoryPath; }
|
||||
QString const repositoryPath() const { return m_repositoryPath; }
|
||||
|
||||
private:
|
||||
static QString jsonType(enum FileTypeJson type);
|
||||
|
||||
@ -69,6 +92,7 @@ private:
|
||||
bool stopBootloader() const;
|
||||
bool openSerial(int br, QString baudrate, QString comPort) const;
|
||||
void closeSerial() const;
|
||||
bool isSerialOpen() const;
|
||||
bool resetDeviceController() const;
|
||||
QByteArray loadBinaryDCFile(QString filename) const;
|
||||
bool downloadBinaryToDC(QString const &bFile) const;
|
||||
@ -81,6 +105,8 @@ private:
|
||||
bool downloadJson(enum FileTypeJson type, int templateIdx,
|
||||
QString jsFileToSendToDC) const;
|
||||
|
||||
bool executeProcess(QString const &cmd);
|
||||
|
||||
private slots:
|
||||
void readyReadStandardOutput();
|
||||
void readyReadStandardError();
|
||||
|
311
worker.cpp
311
worker.cpp
@ -7,20 +7,37 @@
|
||||
#include <QTimer>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QThread>
|
||||
#include <QRegularExpression>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "plugins/interfaces.h"
|
||||
#include "ismas/ismas_client.h"
|
||||
#include "apism/apism_client.h"
|
||||
|
||||
|
||||
Worker::Worker(QString update_ctrl_file, QString workingDir)
|
||||
: m_update_ctrl_file(update_ctrl_file)
|
||||
, m_workingDir(workingDir)
|
||||
, m_workerThread("workerThread") {
|
||||
|
||||
Worker::Worker(hwinf *hw, QString update_ctrl_file, QString repositoryPath,
|
||||
QString customerId, QString branchName, QString workingDirectory, bool maintenanceMode,
|
||||
bool testMode, bool executeScriptOnly, bool dryRun, QObject *parent,
|
||||
char const *serialInterface, char const *baudrate)
|
||||
: m_workerThread("workerThread")
|
||||
, m_apismClient(0, 0, 0, this) // TODO
|
||||
, m_gc(repositoryPath, customerId, workingDirectory, branchName, this)
|
||||
, m_customerId(customerId)
|
||||
, m_workingDirectory(workingDirectory)
|
||||
, m_branchName(branchName)
|
||||
, m_customerRepository(QDir::cleanPath(m_workingDirectory
|
||||
+ QDir::separator()
|
||||
+ m_customerId))
|
||||
, m_maintenanceMode(maintenanceMode)
|
||||
, m_ismasUpdateRequests(ISMAS_UPDATE_REQUESTS)
|
||||
, m_waitForNewUpdates(this) {
|
||||
this->moveToThread(&m_workerThread);
|
||||
//m_apismClient.moveToThread(&m_workerThread);
|
||||
|
||||
m_workerThread.start();
|
||||
QThread::usleep(100000);
|
||||
|
||||
int cnt = 0;
|
||||
while (!m_workerThread.isRunning()) {
|
||||
@ -31,10 +48,41 @@ Worker::Worker(QString update_ctrl_file, QString workingDir)
|
||||
QThread::sleep(1);
|
||||
}
|
||||
|
||||
connect(this, SIGNAL(workNow()), this, SLOT(work()), Qt::QueuedConnection);
|
||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
m_timer.setSingleShot(true);
|
||||
m_timer.start(1000);
|
||||
m_update = new Update(hw, update_ctrl_file, repositoryPath, customerId,
|
||||
branchName, workingDirectory,
|
||||
maintenanceMode, testMode, executeScriptOnly, dryRun,
|
||||
parent, serialInterface, baudrate);
|
||||
|
||||
connect(&m_apismClient, SIGNAL(ismasResponseAvailable(QJsonObject)), this,
|
||||
SLOT(onIsmasResponseReceived(QJsonObject)));
|
||||
|
||||
connect(this, SIGNAL(executeOpkgCommands(QStringList)), this,
|
||||
SLOT(onExecuteOpkgCommands(QStringList)), Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(executeOpkgCommand(QString)), this,
|
||||
SLOT(onExecuteOpkgCommand(QString)), Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(summarizeRepositoryStatus()), this,
|
||||
SLOT(onSummarizeRepositoryStatus()), Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(sendCmdSendVersionToIsmas()), this,
|
||||
SLOT(onSendCmdSendVersionToIsmas()), Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(summarizeUpload(QStringList)), this,
|
||||
SLOT(onSummarizeUpload(QStringList)), Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(handleChangedFiles(QStringList)), this,
|
||||
SLOT(onHandleChangedFiles(QStringList)), Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(finishUpdateProcess(bool)), this,
|
||||
SLOT(onFinishUpdateProcess(bool)), Qt::QueuedConnection);
|
||||
connect(this, SIGNAL(terminateUpdateProcess()), this,
|
||||
SLOT(onTerminateUpdateProcess()), Qt::QueuedConnection);
|
||||
|
||||
//connect(this, SIGNAL(workNow()), this, SLOT(work()), Qt::QueuedConnection);
|
||||
connect(&m_startUpdateProcess, SIGNAL(timeout()), this, SLOT(askIsmasForNewData()), Qt::QueuedConnection);
|
||||
m_startUpdateProcess.setSingleShot(true);
|
||||
m_startUpdateProcess.start(1000);
|
||||
|
||||
connect(&m_waitForNewUpdates, SIGNAL(timeout()), this, SLOT(askIsmasForNewData()), Qt::QueuedConnection);
|
||||
m_waitForNewUpdates.setSingleShot(false);
|
||||
|
||||
m_machineNr = 996;
|
||||
m_customerNr = 281;
|
||||
}
|
||||
|
||||
Worker::~Worker() {
|
||||
@ -48,19 +96,238 @@ Worker::~Worker() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_update) {
|
||||
delete m_update;
|
||||
}
|
||||
}
|
||||
|
||||
void Worker::update() {
|
||||
qCritical() << __func__ << ":" << __LINE__;
|
||||
emit workNow();
|
||||
void Worker::onHandleChangedFiles(QStringList changedFiles) {
|
||||
qCritical() << QDir::currentPath() << "ON HANDLE CHANGED FILES" << changedFiles;
|
||||
if (QDir(m_customerRepository).exists()) {
|
||||
if (QDir::setCurrent(m_customerRepository)) {
|
||||
QString const params("--recursive "
|
||||
"--progress "
|
||||
"--checksum "
|
||||
"--exclude=.* "
|
||||
"--include=*.bin "
|
||||
"--include=*.json "
|
||||
"--include=opkg_commands "
|
||||
"--include=*.ini");
|
||||
QStringList cmds;
|
||||
cmds << QString("rsync ") + params.simplified() + " etc/ /etc";
|
||||
cmds << QString("rsync ") + params.simplified() + " opt/ /opt";
|
||||
|
||||
QString cmd;
|
||||
bool error = false;
|
||||
foreach (cmd, cmds) {
|
||||
if (!error) {
|
||||
Command c("bash");
|
||||
qInfo() << "EXCUTING CMD..." << cmd;
|
||||
if (c.execute(m_customerRepository, QStringList() << "-c" << cmd)) {
|
||||
qDebug() << c.getCommandResult();
|
||||
} else {
|
||||
qCritical() << "CMD" << cmd << "FAILED";
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!error) {
|
||||
onFinishUpdateProcess(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
onTerminateUpdateProcess();
|
||||
}
|
||||
|
||||
void Worker::work() {
|
||||
qCritical() << __func__ << ":" << __LINE__;
|
||||
//Update m_update(m_update_ctrl_file, m_workingDir);
|
||||
QThread::sleep(3);
|
||||
//if (m_update.doUpdate()) {
|
||||
//}
|
||||
m_workerThread.quit();
|
||||
QApplication::quit();
|
||||
void Worker::onSummarizeUpload(QStringList changedFiles) {
|
||||
QDateTime const c = QDateTime::currentDateTime();
|
||||
QDate const d = c.date();
|
||||
QTime const t = c.time();
|
||||
|
||||
QString uploadHistoryFile = QString("upload_history_%1%2%3T%4%5%6.txt")
|
||||
.arg(d.year()).arg(d.month()).arg(d.day())
|
||||
.arg(t.hour()).arg(t.minute()).arg(t.second());
|
||||
|
||||
QFile f(uploadHistoryFile);
|
||||
if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&f);
|
||||
QString fName;
|
||||
foreach (fName, changedFiles) {
|
||||
QString lastCommit = m_gc.gitLastCommit(fName);
|
||||
out << fName << ":" << lastCommit << "\n";
|
||||
}
|
||||
} else {
|
||||
// TODO: error an ISMAS
|
||||
}
|
||||
}
|
||||
|
||||
void Worker::onSummarizeRepositoryStatus() {
|
||||
// TODO
|
||||
QString dir("/opt/app/tools/atbupdate/customer_999");
|
||||
QDirIterator it(dir, QStringList() << "*.jpg",
|
||||
QDir::Files, QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
qDebug() << it.next();
|
||||
if (m_gc.gitIsFileTracked(it.next())) {
|
||||
QString lastCommit = m_gc.gitLastCommit(it.next());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
QString repoStatusHistoryFile = QString("repo_status_history_%1%2%3T%4%5%6.txt")
|
||||
.arg(d.year()).arg(d.month()).arg(d.day())
|
||||
.arg(t.hour()).arg(t.minute()).arg(t.second());
|
||||
if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&f);
|
||||
QString fName;
|
||||
foreach (fName, changedFiles) {
|
||||
QString lastCommit = m_gc.gitLastCommit(fName);
|
||||
out << fName << ":" << lastCommit << "\n";
|
||||
}
|
||||
} else {
|
||||
// TODO: error an ISMAS
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void Worker::onExecuteOpkgCommands(QStringList opkgCommands) {
|
||||
QString opkgCommand;
|
||||
foreach (opkgCommand, opkgCommands) {
|
||||
emit this->executeOpkgCommand(opkgCommand);
|
||||
}
|
||||
}
|
||||
|
||||
void Worker::onExecuteOpkgCommand(QString opkgCommand) {
|
||||
Command c(opkgCommand);
|
||||
if (c.execute(m_workingDirectory)) {
|
||||
QString const r = c.getCommandResult();
|
||||
qDebug() << opkgCommand << ": RESULT" << r;
|
||||
}
|
||||
}
|
||||
|
||||
// sollte ParameterResponse heissen
|
||||
void Worker::onIsmasResponseReceived(QJsonObject ismasResponse) {
|
||||
|
||||
if (!ismasResponse.isEmpty()) {
|
||||
QStringList const keys = ismasResponse.keys();
|
||||
static QRegularExpression re("^REQ_ISMASPARAMETER.*");
|
||||
if(keys.indexOf(re) >= 0) {
|
||||
m_waitForNewUpdates.stop(); // stop asking ISMAS for updates
|
||||
|
||||
// sanity check: cust_nr and machine_nr of PSA correct ?
|
||||
if (keys.contains("Dev_ID", Qt::CaseInsensitive)) {
|
||||
QJsonObject const devId = ismasResponse["Dev_ID"].toObject();
|
||||
QStringList const keys = devId.keys();
|
||||
if (keys.contains("Custom_ID") && keys.contains("Device_ID")) {
|
||||
QJsonValue const c = devId.value("Custom_ID");
|
||||
QJsonValue const m = devId.value("Device_ID");
|
||||
int customerNr = c.toInt(-1);
|
||||
int machineNr = m.toInt(-1);
|
||||
if (customerNr != m_customerNr) {
|
||||
qCritical() << "CUSTOMER-NR (" << customerNr << ") !="
|
||||
<< "LOCAL CUSTOMER-NR (" << m_customerNr << ")";
|
||||
m_updateStatus = UPDATE_STATUS::ERROR_BACKEND;
|
||||
return;
|
||||
}
|
||||
if (machineNr != m_machineNr) {
|
||||
qCritical() << "MACHINE-NR (" << machineNr << ") !="
|
||||
<< "LOCAL MACHINE-NR (" << m_machineNr << ")";
|
||||
m_updateStatus = UPDATE_STATUS::ERROR_BACKEND;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keys.contains("Fileupload", Qt::CaseInsensitive)) {
|
||||
QJsonObject fileUpload = ismasResponse["Fileupload"].toObject();
|
||||
QJsonValue v = fileUpload.value("TRG");
|
||||
if (!v.isNull() && !v.isUndefined()) {
|
||||
QString const s = v.toString("");
|
||||
if (s == "WAIT") {
|
||||
m_ismasUpdateRequests = ISMAS_UPDATE_REQUESTS;
|
||||
qCritical() << "ISMAS UPDATES AVAILABLE";
|
||||
emit m_gc.ismasUpdatesAvailable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Worker::onFinishUpdateProcess(bool changes) {
|
||||
qCritical() << "ON FINISH UPDATE PROCESS. CHANGES=" << changes;
|
||||
m_workerThread.quit();
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
|
||||
void Worker::onTerminateUpdateProcess() {
|
||||
qCritical() << "ON TERMINATE UPDATE PROCESS";
|
||||
m_workerThread.quit();
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
void Worker::onSendCmdSendVersionToIsmas() {
|
||||
|
||||
QString const tariffVersion = "0.0.1";
|
||||
QString const tariffProject = "test_project";
|
||||
int tariffZone = 1;
|
||||
QString const tariffInfo = "test_tariff_info";
|
||||
QString const tariffLoadTime = QDateTime::currentDateTime().toString(Qt::ISODateWithMs);
|
||||
QString const linuxVersion = "test_linux_version";
|
||||
QString const cpuSerial = "test_cpu_serial";
|
||||
QString const deviceControllerVersion = "test_dc_version";
|
||||
QString const deviceControllerGitBlob = "test_dc_blob_2a3b4f50";
|
||||
QString const deviceControllerGitLastCommit = "test_dc_commit_12345abc";
|
||||
QString const raucVersion = "test_rauc_version";
|
||||
QString const opkgVersion = "test_opkg_version";
|
||||
QString const atbQTVersion = "test_qtbqt_version";
|
||||
QString const atbQTGitDescribe = "test_atbqt_git_describe";
|
||||
QString const deviceControllerPluginVersion = "test_CAmaster_version";
|
||||
QString const ingenicoISelfCCPluginVersion = "test_ingenico_plugin_version";
|
||||
QString const mobilisisCalculatePricePluginVersion = "test_mobilisis_plugin_version";
|
||||
QString const mobilisisCalculatePriceConfigUiVersion = "test_mobilisis_config_ui_plugin";
|
||||
QString const prmCalculatePricePluginVersion = "test_prm_calculate_price_plugin";
|
||||
QString const prmCalculatePriceConfigUiPluginVersion = "test_prm_calculate_price_config_ui_plugin";
|
||||
QString const tcpZVTPluginVersion = "test_tcp_zvt_plugin";
|
||||
|
||||
QString data = m_ismasClient.updateOfPSASendVersion(tariffVersion,
|
||||
tariffProject,
|
||||
tariffZone,
|
||||
tariffInfo,
|
||||
tariffLoadTime,
|
||||
linuxVersion,
|
||||
cpuSerial,
|
||||
deviceControllerVersion,
|
||||
deviceControllerGitBlob,
|
||||
deviceControllerGitLastCommit,
|
||||
raucVersion,
|
||||
opkgVersion,
|
||||
atbQTVersion,
|
||||
atbQTGitDescribe,
|
||||
deviceControllerPluginVersion,
|
||||
ingenicoISelfCCPluginVersion,
|
||||
mobilisisCalculatePricePluginVersion,
|
||||
mobilisisCalculatePriceConfigUiVersion,
|
||||
prmCalculatePricePluginVersion,
|
||||
prmCalculatePriceConfigUiPluginVersion,
|
||||
tcpZVTPluginVersion);
|
||||
m_apismClient.sendCmdSendVersionToIsmas(data);
|
||||
}
|
||||
|
||||
void Worker::askIsmasForNewData() {
|
||||
if (m_maintenanceMode) {
|
||||
QString data = m_ismasClient.setUpdatesAvailable();
|
||||
m_apismClient.sendUpdateInfoToIsmas(data);
|
||||
}
|
||||
m_apismClient.requestAvailableIsmasUpdates();
|
||||
|
||||
if (--m_ismasUpdateRequests > 0) {
|
||||
// if the timer is already running, it will be stopped and restarted.
|
||||
m_waitForNewUpdates.start(10000);
|
||||
} else {
|
||||
qCritical() << "REQUESTING ISMAS FOR UPDATES TIMED OUT";
|
||||
m_workerThread.quit();
|
||||
QApplication::quit();
|
||||
}
|
||||
}
|
||||
|
84
worker.h
84
worker.h
@ -3,28 +3,98 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include <QFile>
|
||||
#include <QJsonObject>
|
||||
#include <QHash>
|
||||
|
||||
#include "worker_thread.h"
|
||||
#include "update.h"
|
||||
#include "git/git_client.h"
|
||||
#include "ismas/ismas_client.h"
|
||||
#include "apism/apism_client.h"
|
||||
|
||||
#ifdef PTU5
|
||||
#define SERIAL_PORT "ttymxc2"
|
||||
#else
|
||||
#define SERIAL_PORT "ttyUSB0"
|
||||
#endif
|
||||
|
||||
|
||||
class hwinf;
|
||||
class Worker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
QString m_update_ctrl_file;
|
||||
QString m_workingDir;
|
||||
WorkerThread m_workerThread;
|
||||
QTimer m_timer;
|
||||
QTimer m_startUpdateProcess;
|
||||
Update *m_update;
|
||||
ApismClient m_apismClient;
|
||||
GitClient m_gc;
|
||||
QString const m_customerId;
|
||||
QString const m_workingDirectory;
|
||||
QString const m_branchName;
|
||||
QString const m_customerRepository;
|
||||
bool m_maintenanceMode;
|
||||
int m_ismasUpdateRequests;
|
||||
QTimer m_waitForNewUpdates;
|
||||
IsmasClient m_ismasClient;
|
||||
|
||||
int m_machineNr; // setzen
|
||||
int m_customerNr;
|
||||
|
||||
|
||||
enum { ISMAS_UPDATE_REQUESTS = 6 };
|
||||
|
||||
enum class UPDATE_STATUS : quint8 {
|
||||
STARTED,
|
||||
STOPPED,
|
||||
ERROR_BACKEND
|
||||
} m_updateStatus;
|
||||
|
||||
public:
|
||||
explicit Worker(QString update_ctrl_file, QString workingDir);
|
||||
explicit Worker(hwinf *hw,
|
||||
QString update_ctrl_file,
|
||||
QString repositoryPath,
|
||||
QString customerId,
|
||||
QString branchName,
|
||||
QString workingDir = ".",
|
||||
bool maintenanceMode = false,
|
||||
bool testMode = false,
|
||||
bool executeScriptOnly = false,
|
||||
bool dryRun = false,
|
||||
QObject *parent = nullptr,
|
||||
char const *serialInterface = SERIAL_PORT,
|
||||
char const *baudrate = "115200");
|
||||
~Worker();
|
||||
void quit() { return m_workerThread.quit(); }
|
||||
|
||||
signals:
|
||||
void workNow();
|
||||
void executeOpkgCommands(QStringList);
|
||||
void executeOpkgCommand(QString);
|
||||
void handleChangedFiles(QStringList);
|
||||
void summarizeUpload(QStringList);
|
||||
void summarizeRepositoryStatus();
|
||||
void sendCmdSendVersionToIsmas();
|
||||
void finishUpdateProcess(bool changes);
|
||||
void terminateUpdateProcess();
|
||||
|
||||
public slots:
|
||||
void work();
|
||||
void update();
|
||||
void onIsmasResponseReceived(QJsonObject ismasResponse);
|
||||
void onExecuteOpkgCommands(QStringList opkgCommands);
|
||||
void onExecuteOpkgCommand(QString opkgCommand);
|
||||
|
||||
private slots:
|
||||
void askIsmasForNewData();
|
||||
void onSendCmdSendVersionToIsmas();
|
||||
void onSummarizeRepositoryStatus();
|
||||
void onFinishUpdateProcess(bool changes);
|
||||
void onTerminateUpdateProcess();
|
||||
void onSummarizeUpload(QStringList);
|
||||
void onHandleChangedFiles(QStringList);
|
||||
};
|
||||
|
||||
//Q_DECLARE_METATYPE((QHash<QString, QString>))
|
||||
//Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QHash)
|
||||
|
||||
#endif // WORKER_H_INCLUDED
|
||||
|
Loading…
x
Reference in New Issue
Block a user