Compare commits

..

31 Commits

Author SHA1 Message Date
18ff5d42a7 Merge branch 'pu/integration' into pu/accountRequest 2023-06-19 16:41:08 +02:00
ac9486879e Update interfaces.h (20230619_1623) 2023-06-19 16:40:12 +02:00
1467530e3c Add debug output for account request 2023-06-19 16:27:20 +02:00
414dda009e Proposal for getting account data from CAlib/DeviceController 2023-06-19 16:26:33 +02:00
74753ce644 Add utils-class for static utils methods 2023-06-19 15:07:05 +02:00
c4cbf89182 TEST: try to track currentCashState
... but this is currently useless because we can not detect overpayment
here.
2023-06-16 15:50:25 +02:00
0baad4689a Add note about TODO: TicketNumber 2023-06-16 15:49:56 +02:00
a4a746658c TEST: use QueuedConnection for hwapi signals 2023-06-16 11:21:24 +02:00
7e65c4feda onPrinterDataPrepared: increase time for fake signal onPrinterFinishedOk 2023-06-16 11:17:38 +02:00
e236fc8bce Update interfaces.h (20230616_08006_08006_08006_08006_08006_0800) 2023-06-16 11:14:30 +02:00
76e67dbbaa Fix: return, if CashAgentLib could not be loaded 2023-06-16 10:53:27 +02:00
b52de16dbc Workaround for CashAgent: onCashVendStopByMax()
Wait 500ms until we call hw->getInsertedAmount().
2023-06-15 18:49:59 +02:00
cade03b400 Log output from hw->getInsertedAmount() 2023-06-15 18:49:29 +02:00
7a9f837b88 Refactoring 2023-06-15 18:49:13 +02:00
b10e597e59 Workaround for CashAgent: send 'vend_failed()' on program start 2023-06-15 14:18:32 +02:00
4cc4247744 CashAgent: update errorCodes 2023-06-15 14:16:03 +02:00
59432735d0 CashAgent: changed name: CAmaster 2023-06-15 14:15:13 +02:00
1f0720e52b Update interfaces.h 2023-06-15 13:45:19 +02:00
5f3e0babb1 Load CashAgentLib: print errorString if load fails 2023-06-15 10:54:32 +02:00
f2637e3af8 dc_autoRequest is allways switched on 2023-06-15 09:48:25 +02:00
ac6331e5a7 Update interfaces.h (20230615) 2023-06-15 09:47:17 +02:00
7ccbc8bb23 Proposal for requestAccount() (does not work)
... because of random signal from DeviceController.
... and wrong handling of DeviceController methods.
2023-06-14 14:38:24 +02:00
017543dd5b Door Events: Update log outputs 2023-06-14 14:37:34 +02:00
d5d2b8917a Add handling door events 2023-06-13 17:00:17 +02:00
9d686ae48d Update DeviceControllerInterface (door events) 2023-06-13 16:59:20 +02:00
a037626d6d Update interface.h (door events) 2023-06-13 16:58:17 +02:00
a3f32b576e Set dateTime on plugin init 2023-06-12 09:51:34 +02:00
668b10e55d Add interface for programmode switch 2023-06-12 09:51:16 +02:00
596cf3ed25 TicketPrint: select ticket to print
dependent on printingData.
2023-06-09 11:19:39 +02:00
c330be4f30 TicketPrint: use interface method 'prn_printKombiticket()'
... instead of printing templates.
2023-06-09 11:18:39 +02:00
3722dd4d28 Merge branch 'pu/use_cashAgentLib' into pu/integration 2023-06-06 10:14:42 +02:00
7 changed files with 881 additions and 967 deletions

View File

@@ -73,11 +73,13 @@ HEADERS += \
src/ATBAPP/ATBAPPplugin.h \
src/ATBAPP/DeviceControllerInterface.h \
src/ATBAPP/ATBHealthEvent.h \
src/ATBAPP/ATBDeviceControllerPlugin.h
src/ATBAPP/ATBDeviceControllerPlugin.h \
src/ATBAPP/Utils.h
SOURCES += \
src/ATBAPP/ATBHealthEvent.cpp \
src/ATBAPP/ATBDeviceControllerPlugin.cpp
src/ATBAPP/ATBDeviceControllerPlugin.cpp \
src/ATBAPP/Utils.cpp
DISTFILES += \
generate-version.sh

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
#include "src/ATBAPP/ATBDeviceControllerPlugin.h"
#include "src/ATBAPP/ATBHealthEvent.h"
#include "src/ATBAPP/Utils.h"
#include <QTimer>
#include <QTextCodec>
@@ -7,6 +8,10 @@
#include <QPluginLoader>
#include <QDateTime>
#include <QFileInfo>
#include <cstdlib>
ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent) : QObject(parent),
@@ -21,14 +26,25 @@ ATBDeviceControllerPlugin::ATBDeviceControllerPlugin(QObject *parent) : QObject(
//connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_templatePrintFinished_OK()), this, SLOT(onPrintFinishedOK()));
//connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_templatePrintFinished_Err()), this, SLOT(onPrintFinishedERR()));
//connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_templatePrintFinished_OK()), this, SLOT(onPrintFinishedOK()), Qt::QueuedConnection);
//connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_templatePrintFinished_Err()), this, SLOT(onPrintFinishedERR()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_gotNewCoin()), this, SLOT(onCashGotCoin()));
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByMax()), this, SLOT(onCashPayStopByMax()));
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByEscrow()), this, SLOT(onCashPayStopByEscrow()));
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByError()), this, SLOT(onCashPayStopByError()));
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByTimeout()), this, SLOT(onCashPayStopByTimeout()));
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_gotNewCoin()), this, SLOT(onCashGotCoin()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByMax()), this, SLOT(onCashPayStopByMax()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByEscrow()), this, SLOT(onCashPayStopByEscrow()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByError()), this, SLOT(onCashPayStopByError()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_payStopByTimeout()), this, SLOT(onCashPayStopByTimeout()), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorServiceDoorOpened()), this, SLOT(onServiceDoorOpened()), Qt::QueuedConnection); // switch to ModeSERVICE
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorVaultDoorOpened()), this, SLOT(onVaultDoorOpened()), Qt::QueuedConnection); // Screen?? with message
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorCoinBoxRemoved()), this, SLOT(onCoinBoxRemoved()), Qt::QueuedConnection); // Create/Send Account
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorCoinBoxInserted()), this, SLOT(onCoinBoxInserted()), Qt::QueuedConnection);
//connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorCBinAndAllDoorsClosed()), this, SLOT( ??? )), Qt::QueuedConnection);
connect(dynamic_cast<QObject*>(hw), SIGNAL(hwapi_doorAllDoorsClosed()), this, SLOT(onAllDoorsClosed()), Qt::QueuedConnection); // check for errors, switch to mode IDLE
this->currentSelectedTicketType = 0;
this->currentCashState = CASH_STATE::CACHE_EMPTY;
}
ATBDeviceControllerPlugin::~ATBDeviceControllerPlugin() {}
@@ -41,11 +57,15 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *healthEventReceive
QString serialPort = settings.value("DEVICE_CONTROLLER/serialPort", "ttymxc2").toString();
QByteArray printerEncoding = settings.value("DEVICE_CONTROLLER/printerEnconding", "ISO 8859-2").toString().toLatin1();
// open serial port
hw->dc_openSerial(5, "115200", serialPort, 1);
hw->dc_autoRequest(true);
// open serial port
hw->dc_openSerial(5, "115200", serialPort, 1);
hw->rtc_setDateTime();
// this is necessary to init the CashAgentLib (!)
hw->vend_failed();
// text encoding for printer
@@ -59,6 +79,29 @@ PLUGIN_STATE ATBDeviceControllerPlugin::initDCPlugin(QObject *healthEventReceive
}
// Handle Mode-Changes --------------------------------------------------------
void ATBDeviceControllerPlugin::onChangedProgramModeToSELL()
{
//hw->dc_autoRequest(true);
}
void ATBDeviceControllerPlugin::onChangedProgramModeToSERVICE()
{
//hw->dc_autoRequest(true);
}
void ATBDeviceControllerPlugin::onChangedProgramModeToIDLE()
{
//hw->dc_autoRequest(false); // <-- TODO: ???
}
void ATBDeviceControllerPlugin::onChangedProgramModeToOOO()
{
}
// TASKS: Cash handling -------------------------------------------------------
void ATBDeviceControllerPlugin::requestStartCashInput(const QString & amount)
{
@@ -76,23 +119,149 @@ void ATBDeviceControllerPlugin::requestStopCashInput()
hw->cash_stopPayment();
// we need new cash value in application...
QTimer::singleShot(500, this, SLOT(onCashPayStoped()));
QTimer::singleShot(500, this, SLOT(onCashPayStopedSuccess()));
}
void ATBDeviceControllerPlugin::cashCollect()
{
hw->vend_success();
this->currentCashState = CASH_STATE::CACHE_EMPTY;
}
void ATBDeviceControllerPlugin::cashAbort()
{
hw->vend_failed();
this->currentCashState = CASH_STATE::CACHE_EMPTY;
}
// TASKS: Account -------------------------------------------------------------
// for an external account request, e.g. by an ui-button:
void ATBDeviceControllerPlugin::requestAccount()
{
qCritical() << "TODO: implement ATBDeviceControllerPlugin::requestAccount()";
qCritical() << "ATBDeviceControllerPlugin::requestAccount()";
this->private_startAccount();
}
void ATBDeviceControllerPlugin::private_startAccount()
{
uint16_t backupedAccNumbers[8]; // array of account numbers
uint8_t nrOfVals; // number of saved accounts
// it is not defined which one is the latest account
hw->log_getHoldAccountNumbers(&nrOfVals, backupedAccNumbers);
// DEBUG
qCritical() << "Start account: ";
qCritical() << " nrOfVals = " << nrOfVals;
for (int i=0; i<nrOfVals; ++i) {
qCritical() << " backupedAccNumbers[" << i << "] = " << backupedAccNumbers[0];
}
qsort( backupedAccNumbers, nrOfVals, sizeof (uint16_t), Utils::compare );
uint16_t latestAccountNumber = backupedAccNumbers[nrOfVals-1];
// DEBUG
qCritical() << " latestAccountNumber = " << latestAccountNumber;
hw->log_selectVaultRecord(latestAccountNumber);
this->accountCheckCounter = 0;
QTimer::singleShot(500, this, SLOT(private_checkAccountData()));
}
void ATBDeviceControllerPlugin::private_checkAccountData()
{
// DEBUG
qCritical() << " --> private_checkAccountData()";
if (hw->log_chkIfVaultRecordAvailable()) {
this->private_getAccountData();
}
else {
if (this->accountCheckCounter < 10) {
this->accountCheckCounter++;
QTimer::singleShot(500, this, SLOT(private_checkAccountData()));
}
else {
// cannot get accountData within ~10*500ms
qCritical() << "checkAccountData() failed";
// TODO: create and send an HealthEvent...
}
}
}
void ATBDeviceControllerPlugin::private_getAccountData()
{
// DEBUG
qCritical() << " --> private_getAccountData()";
struct T_vaultRecord retVR;
hw->log_getVaultRecord(&retVR);
QHash<QString, QVariant> accountData;
accountData.insert("AccountingNumber", QString::number(retVR.AccountingNumber));
for (uint i = 0; i < sizeof(retVR.coinsInVault); ++i) {
accountData.insert("COIN_" + QString::number(i) + "_Quantity", retVR.coinsInVault[i]);
accountData.insert("COIN_" + QString::number(i) + "_Value", retVR.coinDenomination[i]);
// DEBUG
qCritical() << "COIN_" + QString::number(i) + "_Quantity = " << accountData["COIN_" + QString::number(i) + "_Quantity"];
qCritical() << "COIN_" + QString::number(i) + "_Value = " << accountData["COIN_" + QString::number(i) + "_Value"];
}
emit requestAccountResponse(accountData);
}
// Door Events / Hardware contacts --------------------------------------------
void ATBDeviceControllerPlugin::onServiceDoorOpened()
{
qCritical() << "ATBDeviceControllerPlugin::onServiceDoorOpened()";
// switch to mode service
emit this->requestModeSERVICE();
// TODO:
// - create an HealthEvent (-> ISMAS-Event)
}
void ATBDeviceControllerPlugin::onVaultDoorOpened()
{
// TODO:
// - show special screen / message on screen
// - create an HealthEvent (-> ISMAS-Event)
qCritical() << "ATBDeviceControllerPlugin::onVaultDoorOpened()";
}
void ATBDeviceControllerPlugin::onCoinBoxRemoved()
{
qCritical() << "ATBDeviceControllerPlugin::onCoinBoxRemoved()";
this->private_startAccount();
}
void ATBDeviceControllerPlugin::onCoinBoxInserted()
{
qCritical() << "ATBDeviceControllerPlugin::onCoinBoxInserted()";
}
void ATBDeviceControllerPlugin::onAllDoorsClosed()
{
// TODO:
// - check for errors, switch to mode IDLE
qCritical() << "ATBDeviceControllerPlugin::onAllDoorsClosed()";
emit this->requestModeIDLE();
}
@@ -154,8 +323,6 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
}
// TODO: wird hier nur 'licensePlate' gedruckt?
if (!this->hw->prn_sendDynamicPrnValues(dynTicketData->licensePlate)) {
this->errorCode = "hwapi::prn_sendDynamicPrnValues";
@@ -174,6 +341,38 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
return;
}
// set ticket type:
// 00281 - Szeged:
// 1 - Cash / ShortTimeParking
// 2 - Card / ShortTimeParking
// 3 - Cash / DayTicket
// 4 - Card / DayTicket
QString paymentType = printingData["paymentType"].toString(); // must be "CASH" | "CARD"
QString productName = printingData["product"].toString(); // must be "ShortTimeParking" | "DayTicket"
if ( (paymentType == "CASH") && (productName == "ShortTimeParking") ) {
this->currentSelectedTicketType = 1;
}
else
if ( (paymentType == "CARD") && (productName == "ShortTimeParking") ) {
this->currentSelectedTicketType = 2;
}
else
if ( (paymentType == "CASH") && (productName == "DayTicket") ) {
this->currentSelectedTicketType = 3;
}
else
if ( (paymentType == "CARD") && (productName == "DayTicket") ) {
this->currentSelectedTicketType = 4;
}
else {
qCritical() << "ERROR: requestPrintTicket(): invalid payment data:";
qCritical() << " paymentType = " << paymentType << endl
<< " productName = " << productName << endl;
this->onPrintFinishedERR();
return;
}
QTimer::singleShot(1000, this, SLOT(onPrinterDataPrepared()));
}
@@ -181,8 +380,15 @@ void ATBDeviceControllerPlugin::requestPrintTicket(const QHash<QString, QVariant
void ATBDeviceControllerPlugin::onPrinterDataPrepared()
{
this->currentTemplate = 1;
this->onPrinterPrintNextTemplate();
this->hw->prn_printKombiticket(this->currentSelectedTicketType);
// FAKE SIGNAL:
QTimer::singleShot(4000, this, SLOT(onPrintFinishedOK()));
// old: use printer templates:
// this->currentTemplate = 1;
// this->onPrinterPrintNextTemplate();
}
@@ -223,6 +429,7 @@ void ATBDeviceControllerPlugin::onPrintFinishedOK()
qCritical() << "ATBDeviceControllerPlugin::onPrintFinishedOK()";
emit this->printTicketFinished(nsDeviceControllerInterface::RESULT_STATE::SUCCESS,
// TODO: TicketNumber
"",
"");
}
@@ -250,6 +457,8 @@ void ATBDeviceControllerPlugin::onCashGotCoin()
// DEBUG
qCritical() << "ATBDeviceControllerPlugin::onGotCoin()";
this->currentCashState = CASH_STATE::CACHE_INPUT;
uint32_t amountInt = this->hw->getInsertedAmount();
QString amountString = QString::number(amountInt);
@@ -268,14 +477,8 @@ void ATBDeviceControllerPlugin::onCashPayStopByMax()
// DEBUG
qCritical() << "ATBDeviceControllerPlugin::onCashVendStopByMax()";
uint32_t amountInt = this->hw->getInsertedAmount();
QString amountString = QString::number(amountInt);
emit this->cashInputFinished(nsDeviceControllerInterface::RESULT_STATE::SUCCESS,
amountString,
"",
"");
// we need new cash value in application...
QTimer::singleShot(500, this, SLOT(onCashPayStopedSuccess()));
}
@@ -324,7 +527,7 @@ void ATBDeviceControllerPlugin::onCashPayStopByTimeout()
"");
}
void ATBDeviceControllerPlugin::onCashPayStoped()
void ATBDeviceControllerPlugin::onCashPayStopedSuccess()
{
// DEBUG
qCritical() << "ATBDeviceControllerPlugin::onCashPayStoped()";
@@ -333,6 +536,9 @@ void ATBDeviceControllerPlugin::onCashPayStoped()
QString amountString = QString::number(amountInt);
qCritical() << " insertedAmount (int) = " << amountInt;
qCritical() << " insertedAmount = " << amountString;
emit this->cashInputFinished(nsDeviceControllerInterface::RESULT_STATE::SUCCESS,
amountString,
"",
@@ -350,12 +556,31 @@ void ATBDeviceControllerPlugin::onCashPayStoped()
bool ATBDeviceControllerPlugin::private_loadCashAgentLib(QString pluginName)
{
if (pluginName == "") {
pluginName = "/usr/lib/libCashAgentLib.so";
// search list for plugin (.so) file:
QStringList pluginNameList;
pluginNameList << "/usr/lib/libCAmaster.so"
<< "/usr/lib/libCashAgentLib.so";
// using C++11 range based loop:
for (const auto& filename : pluginNameList) {
if (QFileInfo(filename).isReadable()) {
pluginName = filename;
break;
}
}
if (pluginName == "") {
qCritical() << "ATBDeviceControllerPlugin: CashAgentLib not installed!";
this->errorCode = "CashAgentLib::NOT_FOUND";
this->errorDescription = "ERROR: no CashAgentLib: ";
return false;
}
}
if (!QLibrary::isLibrary(pluginName)) {
qCritical() << "ATBDeviceControllerPlugin: can not load CashAgentLib: " << pluginName;
this->errorCode = 5;
this->errorCode = "CashAgentLib::NO_LIBRARY";
this->errorDescription = "ERROR: can not load CashAgentLib: " + pluginName;
return false;
}
@@ -366,13 +591,16 @@ bool ATBDeviceControllerPlugin::private_loadCashAgentLib(QString pluginName)
QObject* plugin = pluginLoader->instance();
if (!pluginLoader->isLoaded()) {
qCritical() << "ATBDeviceControllerPlugin: can not instantiate CashAgentLib: " << pluginName;
this->errorCode = 6;
qCritical() << " error: " << pluginLoader->errorString();
this->errorCode = "CashAgentLib::NO_INSTANCE";
this->errorDescription = "ERROR: can not instantiate CashAgentLib: " + pluginName;
return false;
}
if (plugin == nullptr) {
qCritical() << "ATBDeviceControllerPlugin: plugin is NULL";
this->errorCode = "CashAgentLib::INSTANCE_IS_NULL";
this->errorDescription = "ERROR: CashAgentLib instance is NULL: " + pluginName;
}
qCritical() << "ATBDeviceControllerPlugin: instantiate CashAgentLib: " << pluginName;
@@ -381,8 +609,13 @@ bool ATBDeviceControllerPlugin::private_loadCashAgentLib(QString pluginName)
if (this->hw == nullptr) {
qCritical() << "ATBDeviceControllerPlugin: hw is NULL";
this->errorCode = "CashAgentLib::HW_IS_NULL";
this->errorDescription = "ERROR: CashAgentLib object_cast is NULL: " + pluginName;
return false;
}
qCritical() << "ATBDeviceControllerPlugin: loaded CashAgentLib";
return true;
}
@@ -442,8 +675,6 @@ const QString ATBDeviceControllerPlugin::getString(nsDeviceControllerInterface::
}
/************************************************************************************************
* ... end
*/

View File

@@ -62,7 +62,13 @@ public:
const QString & getPluginInfo();
// helpers e.g. for debug / log
const QString getString(nsDeviceControllerInterface::RESULT_STATE resultState);
const QString getString(nsDeviceControllerInterface::RESULT_STATE resultState);;
public slots:
void onChangedProgramModeToSELL();
void onChangedProgramModeToSERVICE();
void onChangedProgramModeToIDLE();
void onChangedProgramModeToOOO();
@@ -84,11 +90,14 @@ signals:
const QString & errorCode,
const QString & errorDescription);
void requestServiceMode();
void requestModeSERVICE();
void requestModeIDLE();
void requestModeOOO();
void requestAccountResponse(const QHash<QString, QVariant> & accountData);
void Error(
const QString & errorCode,
const QString & errorDescription);
@@ -116,6 +125,14 @@ private:
bool private_loadCashAgentLib(QString pluginName);
quint8 currentSelectedTicketType;
nsDeviceControllerInterface::CASH_STATE currentCashState;
// counts failed hw->log_chkIfVaultRecordAvailable()
int accountCheckCounter;
private slots:
// printer
@@ -127,11 +144,23 @@ private slots:
// cash payment
void onCashGotCoin();
void onCashPayStoped();
void onCashPayStopedSuccess();
void onCashPayStopByMax();
void onCashPayStopByEscrow();
void onCashPayStopByError();
void onCashPayStopByTimeout();
// doors and hardware contacts
void onServiceDoorOpened();
void onVaultDoorOpened();
void onCoinBoxRemoved();
void onCoinBoxInserted();
void onAllDoorsClosed();
// account handling
void private_startAccount();
void private_checkAccountData();
void private_getAccountData();
};
#endif // ATBDEVICECONTROLLERPLUGIN_H

View File

@@ -64,6 +64,11 @@ public:
// helpers e.g. for debug / log
virtual const QString getString(nsDeviceControllerInterface::RESULT_STATE resultState) = 0;
public slots:
virtual void onChangedProgramModeToSELL() = 0;
virtual void onChangedProgramModeToSERVICE() = 0;
virtual void onChangedProgramModeToIDLE() = 0;
virtual void onChangedProgramModeToOOO() = 0;
signals:
virtual void printTicketFinished(nsDeviceControllerInterface::RESULT_STATE resultState,
@@ -96,7 +101,17 @@ signals:
/**
* emitted e.g. if service door is opened
*/
virtual void requestServiceMode() = 0;
virtual void requestModeSERVICE() = 0;
/**
* emitted e.g. if doors are closed
*/
virtual void requestModeIDLE() = 0;
/**
* emitted e.g. on severe errors
*/
virtual void requestModeOOO() = 0;
/**
* emitted e.g. if service door is opened

18
src/ATBAPP/Utils.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include "Utils.h"
Utils::Utils(QObject *parent) : QObject(parent)
{
}
int Utils::compare(const void* a, const void* b)
{
int int_a = * ( (int*) a );
int int_b = * ( (int*) b );
if ( int_a == int_b ) return 0;
else if ( int_a < int_b ) return -1;
else return 1;
}

23
src/ATBAPP/Utils.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef UTILS_H
#define UTILS_H
#include <QObject>
class Utils : public QObject
{
Q_OBJECT
public:
static int compare(const void* a, const void* b);
private:
explicit Utils(QObject *parent = nullptr);
signals:
};
#endif // UTILS_H