/*
 * API to the PSA2020 Hardware
 * All data come in from device controller via serial interface and will be stored
 * PI is updated every 100ms
 * This api uses stored data and returns them in the following functions
 * created: Q1/2020 TS until Q2/21
 *
 */

#include <stdint.h>
#include <unistd.h>
#include <thread>
#include <algorithm>

#include <QFileInfo>

#include "tslib.h"
#include "hwapi.h"

#include "sendWRcmd.h"
#include "controlBus.h"
#include "storeINdata.h"
#include "dcBL.h"
#include "shared_mem_buffer.h"
#include <QDebug>
#include <QSharedMemory>
#include "interfaces.h"

static uint32_t hwapi_lastStartAmount;

static const QMap<QString, int> baudrateMap = {
  {"1200"   ,   0}, {"9600"   ,   1}, {"19200"  ,   2}, {"38400"  ,   3},
  {"57600"  ,   4}, {"115200" ,   5}
};

hwapi::hwapi(QObject *parent) : QObject(parent) {
    // create or attach shared memory segment
    // !!! The compoment creating the shared memory MUST be ATBQT !!!
    m_sharedMem = SharedMemBuffer::getShm(sizeof(SharedMemBuffer));
    if (m_sharedMem) {
        if (m_sharedMem->isAttached()) {
            qInfo() << "Shared memory ("
                    << sizeof(SharedMemBuffer) << "bytes) created and attached";
        }
    } else {
        qCritical() << "Creating/attaching shared memory failed";
    }
    sendWRcmd_INI();
    myDatif = new T_datif();

    connect(myDatif, SIGNAL(datif_templatePrintFinished_OK()), this, SLOT(hwapi_slotPrintFinished_OK()));
    connect(myDatif, SIGNAL(datif_templatePrintFinished_Err()), this, SLOT(hwapi_slotPrintFinished_Err()));
    connect(myDatif, SIGNAL(datif_gotNewCoin()), this, SLOT(hwapi_slotGotCoin()));
}

hwapi::~hwapi() {
    if (m_sharedMem && m_sharedMem->isAttached()) {
        m_sharedMem->detach();
    }
}

void hwapi::hwapi_slotPrintFinished_OK(void) {
    emit hwapi_templatePrintFinished_OK();
}

void hwapi::hwapi_slotPrintFinished_Err(void) {
    emit hwapi_templatePrintFinished_Err();
}

void hwapi::hwapi_slotGotCoin(void) {
    // new coin was inserted while transaction and new amount reported:
    emit hwapi_gotNewCoin();

    uint32_t newSum=epi_CurrentPaymentGetAmount();

    if (newSum>=hwapi_lastStartAmount)
        emit hwapi_vendStopByMax();

}

void hwapi::sub_storeSendingText(QByteArray *buf) const {

    char local[70], copie[1350];    // 64byte more then max buffer size!
    int LL, nn, len, maxruns=20;

    epi_resetPrinterStack();
    // make a copy of the incoming byteArray as the byteArray can not be moved (crash!)
    tslib_strclr(copie, 0, 1350);
    LL=buf->length();
    for (nn=0; nn<LL; nn++)
    {
        copie[nn]=buf->at(nn);
    }

    tslib_strclr(local, 0, 66);
    LL=buf->length();
    if (LL>1280)
    {
        qDebug()<<"reducing text size from " << LL << " to 1280 bytes";
        LL=1280;   // Limit size
    } else
        qDebug()<<"\n printing text with " << LL << " bytes: ";

    do
    {
        len=tslib_getMinimum(LL, 64);
        tslib_strclr(local, 0, 66);
        for (nn=0; nn<len; nn++)
        {
            local[nn]=copie[nn];
        }
        local[64]=0;

        // delete already printed part of big buffer
        if (LL<=64)
        {
            // last block
            local[LL]=10;
            // new line = cmd to printer: "print, even if line is not filled"
            LL=0;       // print complete
        } else
        {
            LL-=64;
            for (nn=0; nn<LL; nn++)
            {
                copie[nn]=copie[nn+64];
            }
            // pad remain with 0 (last but one block)
            for (nn=LL; nn<64; nn++)
            {
                copie[nn]=0;
            }
        }


        epi_storePrnText(local, uint8_t(len));    // no need to care for max PI size
            // stores 64byte in PI with every call, maximal 20 calls (1280 byte)

    } while(--maxruns>0 && LL>0);

}


// ------------------------------------------------------------------------------
// Level 0 commands, interface
// open, close, change serial interface
// actually not neccessary as it is opened automatically on program start
// start automatic READ requests
// ------------------------------------------------------------------------------

bool hwapi::dc_openSerial(int BaudNr, QString BaudStr,
                          QString ComName, uint8_t connect) const {
    // BaudNr:  0:1200   1:9600   2:19200   3:38400   4:57600   5:115200
    // BaudStr: for exapmle "19200"
    // ComName: for example "COM48"
    // connect: 0, 1
    //qDebug() << "~~>LIB" << "dc_openSerial called... " ;

    epi_setSerial(BaudNr, BaudStr, ComName, connect);

    // Actions: open serial port with parameters
    for (int i = 0; i < 10; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        if (dc_isPortOpen()) {
            return true;
        }
    }
    return false;
}

QStringList hwapi::dc_getStatus() const {
    QStringList status;

    if (m_sharedMem) {
        SharedMemBuffer const *shMem = SharedMemBuffer::getDataConst();
        status += QString("comport  : %1").arg(shMem->rs.comportName);
        status += QString("baudrate : %1").arg(shMem->rs.baudNr);
        status += QString("baudNr   : %1").arg(shMem->rs.baudStr);
        status += QString("connect  : %1").arg(shMem->rs.connect);
        status += QString("port open: %1").arg(shMem->rs.portIsOpen);
        // to be continued
    }

    return status;
}

bool hwapi::dc_closeSerial(void) const {
    epi_closeSerial();
    for (int i = 0; i < 10; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        if (!dc_isPortOpen()) {
            return true;
        }
    }
    return false;
}

bool hwapi::dc_isPortOpen(void) const {
    if (myDatif) {
        T_prot* prot = myDatif->getProt();
        if (prot) {
            T_com *com = prot->getSerialPort();
            if (com) {
                return com->isPortOpen();
            }
        }
    }
    return false;
    //return epi_isSerialPortOpen();
}

void hwapi::dc_autoRequest(bool on) const
{
    // automatically request ALL digital and analog sensors, get time/date, get status information
    if (on)
        epi_startEmmision(1);
    else
        epi_startEmmision(0);
}

/******************************************************************************/
//
//              LEVEL 2: Help-functions for hwapi::dc_updateDC.
//
/******************************************************************************/
hwapi::DownloadResult hwapi::sendStatus(int ret) const {
    switch (ret) {                      // return values of dc are:
    case 0:                             // 0: no answer by now
        return DownloadResult::NOP;     // 1: error
    case 10:                            // 10: success
        return DownloadResult::OK;
    default:;
    }
    return DownloadResult::ERROR;
}

hwapi::DownloadResult hwapi::sendNextAddress(int bNum) const {
    // sends address only if blockNumber is one of 0, 1024, 2048, 3072, 4096
    int noAnswerCount = 0;
    int errorCount = 0;
    if ( bNum==0 || bNum==1024 || bNum==2048 || bNum==3072 || bNum==4096 ) {
        qDebug() << "addr-block" << bNum << "...";
        while (noAnswerCount <= 250) {
            bl_sendAddress(bNum);
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            DownloadResult const res = sendStatus(bl_wasSendingAddOK());
            if (res != DownloadResult::NOP) {
                if (res == DownloadResult::ERROR) {
                    if (++errorCount >= 10) {
                        qCritical() << "addr-block" << bNum << "...FAILED";
                        return res;
                    }
                } else { // res == DownloadResult::OK
                    qInfo() << "addr-block" << bNum << "...OK";
                    return res;
                }
            } else {
                noAnswerCount += 1; // no answer by now
            }
        }
        // wait max. about 3 seconds
        return DownloadResult::TIMEOUT;
    }
    // blockNumber is not one of 0, 1024, 2048, 3072, 4096 -> do nothing
    return DownloadResult::NOP;
}

hwinf::DownloadResult hwapi::sendNextDataBlock(QByteArray const &binary,
                                               int bNum) const {
    uint8_t local[66];
    int const bAddr = bNum * 64;
    int noAnswerCount = 0;
    int errorCount = 0;

    memcpy(local, binary.constData() + bAddr, 64);
    local[64] = local[65] = 0x00;

    qDebug() << "data for addr" << bAddr << "...";

    while (noAnswerCount <= 250) {
        bl_sendDataBlock(64, local);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        DownloadResult const res = sendStatus(bl_wasSendingDataOK());
        if (res != DownloadResult::NOP) {
            if (res == DownloadResult::ERROR) {
                if (++errorCount >= 10) {
                    qCritical() << "data for addr" << bAddr << "...FAILED";
                    return res;
                }
            } else {
                qInfo() << "data for addr" << bAddr << "...OK";
                return res;
            }
        } else {
            noAnswerCount += 1; // no answer by now
        }
    }
    // wait max. about 3 seconds
    return DownloadResult::TIMEOUT;
}

hwinf::DownloadResult hwapi::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();
    qInfo() << "total number of blocks to send to dc" << nBlocks;

    int bNum = 0;
    DownloadResult res = DownloadResult::OK;
    while (res != DownloadResult::ERROR &&  bNum < nBlocks) {
        if ((res = sendNextAddress(bNum)) != DownloadResult::ERROR) {
            if ((res = sendNextDataBlock(b, bNum)) != DownloadResult::ERROR) {
                bNum += 1;
            }
        }
    }
    if (res != DownloadResult::ERROR) {
        bl_sendLastBlock();
    }
    return res;
}

bool hwapi::startBootloader() const {
    qDebug() << "starting bootloader...";
    int nTry = 5;
    while (--nTry >= 0) {
        bl_startBL();
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        if (bl_isUp()) {
            qInfo() << "starting bootloader...OK";
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
            return true;
        }
    }
    qCritical() << "starting bootloader...FAILED";
    return false;
}

bool hwapi::stopBootloader() const {
    qDebug() << "stopping bootloader...";
    int nTry = 5;
    while (--nTry >= 0) {
        bl_stopBL();
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        if (!bl_isUp()) {
            qInfo() << "stopping bootloader...OK";
            return true;
        }
    }
    qCritical() << "stopping bootloader...FAILED";
    return false;
}

// br is a index into a table, used for historical reasons.
bool hwapi::openSerial(int br, QString baudrate, QString comPort) const {
    qDebug() << "opening serial" << br << baudrate << comPort << "...";
    if (dc_openSerial(br, baudrate, comPort, 1)) { // 1 for connect
        qInfo() << "opening serial" << br << baudrate << comPort << "...OK";
        return true;
    }
    qCritical() << "opening serial" << br << baudrate << comPort << "...FAILED";
    return false;
}

bool hwapi::closeSerial(QString comPort) const {
    qDebug() << "closing serial" << comPort << "...";
    if (dc_closeSerial()) {
        qInfo() << "closing serial" << comPort << "...OK";
        return true;
    } else {
        qCritical() << "closing serial" << comPort << "...FAILED";
    }
    return false;
}

bool hwapi::resetDeviceController() const {
    qDebug() << "resetting device controller...";
    if (stopBootloader()) { // first stop a (maybe) running bootloader
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        dc_OrderToReset();
        // wait maximally 3 seconds, before starting bootloader
        std::this_thread::sleep_for(std::chrono::milliseconds(1500));
        qInfo() << "resetting device controller...OK";
        return true;
    }
    return false;
}

QByteArray hwapi::loadBinaryDCFile(QString filename) const {
    qDebug() << "loading dc binary" << filename << "...";

    QFile file(filename); // closed in destructor call
    if (!file.exists()) {
        qCritical() << file.fileName() << "does not exist";
        return QByteArray();
    }
    if (!file.open(QIODevice::ReadOnly)) {
        qCritical() << "cannot open file" << file.fileName();
        return QByteArray();
    }
    qInfo() << "loading dc binary" << filename << "...OK";
    return file.readAll();
}

bool hwapi::downloadBinaryToDC(QString const &bFile) const {
    qDebug() << "sending" << bFile << "to dc...";
    QByteArray const dcBinary = loadBinaryDCFile(bFile);
    if (dcBinary.size() > 0) {
        if (dc_downloadBinary(dcBinary) != DownloadResult::OK) {
            qCritical() << "sending" << bFile << "to dc...FAILED";
            return false;
        } else {
            qInfo() << "sending" << bFile << "to dc...OK";
        }
    } else {
        qCritical() << "sending" << bFile << "to dc...FAILED";
        qCritical() << "loading binary" << bFile << "FAILED";
        return false;
    }
    return true;
}

/******************************************************************************/
//
//                        LEVEL 3: hwapi::dc_updateDC.
//
/******************************************************************************/
bool hwapi::dc_updateDC(QString bFile, QString br, QString serial) const {
    if (!baudrateMap.contains(br)) { // sanity check
        qCritical() << "passed wrong baudrate" << br;
        return false;
    }

    qDebug() << "updating dc: " << bFile << br << serial << "...";

    if (!openSerial(baudrateMap.value(br), br, serial)) {
        return false;
    }
    if (!resetDeviceController()) {
        closeSerial(serial);
        return false;
    }
    if (!startBootloader()) {
        closeSerial(serial);
        return false;
    }
    if (!downloadBinaryToDC(bFile)) {
        stopBootloader();
        closeSerial(serial);
        qCritical() << "updating dc: " << bFile << br << serial << "...FAILED";
        return false;
    }

    qInfo() << "updating dc: " << bFile << br << serial << "...OK";

    stopBootloader();
    closeSerial(serial);
    return true;
}

/******************************************************************************/
//
//                   LEVEL 3: hwapi::dc_updatePrinterTemplate
//
/******************************************************************************/
bool hwapi::dc_updatePrinterTemplate(enum FileTypeJson type,
                                     QVector<int> templatesIdx,
                                     QVector<QString> fnames,
                                     QString br,
                                     QString serial) const {
    // sanity checks
    if (!baudrateMap.contains(br)) {
        qCritical() << "passed wrong baudrate" << br;
        return false;
    }
    if (templatesIdx.size() != fnames.size()) {
        qCritical() << "list sizes must be equal" << br;
        return false;
    }
    if (!std::all_of(templatesIdx.cbegin(), templatesIdx.cend(),
                    [](int i) { return i >= 1 && i <= 32; })) {
        qCritical() << "wrong template indices";
        return false;
    }
    if (type != FileTypeJson::PRINTER) {
        qCritical() << "wrong file type" << (uint8_t)type;
        return false;
    }

    qDebug() << "updating: " << fnames << br << serial << "...";

    if (!serial.isNull()) {
        if (!openSerial(baudrateMap.value(br), br, serial)) {
            return false;
        }
    }

    int nTry = 50;
    while (!sys_ready4sending()) { // wait max. 5 seconds
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        if (--nTry <= 0) {
            qCritical() << "sys not ready for sending";
            if (!serial.isNull()) {
                closeSerial(serial);
            }
            return false;
        }
    }

    bool ret = true;
    for (int i = 0; i < fnames.size(); ++i) {
        QFile file(fnames[i]);
        if (file.exists() && file.open(QIODevice::ReadOnly)) {
            QByteArray ba = file.readAll();
            if (ba.size() <= 800) { // max. size is 800 bytes
                if (sys_sendJsonFileToDc((uint8_t)(type),
                                          templatesIdx[i],
                                          (uint8_t *)ba.data())) {
                    std::this_thread::sleep_for(std::chrono::seconds(1));
                    qInfo() << "sent file" << fnames[i] << "to dc";
                }
            }
        } else {
            qCritical() << fnames[i] << "!!! does not exist!!!";
            ret = false;
            continue;
        }
    }
    if (!serial.isNull()) {
        closeSerial(serial);
    }
    return ret;
}

bool hwapi::dc_printTemplate(enum FileTypeJson type,
                             QVector<int> templateIdx,
                             QString br,
                             QString serial) const {
    // sanity checks
    if (!baudrateMap.contains(br)) {
        qCritical() << "passed wrong baudrate" << br;
        return false;
    }
    if (!std::all_of(templateIdx.cbegin(), templateIdx.cend(),
                    [](int i) { return i >= 1 && i <= 32; })) {
        qCritical() << "wrong template indices";
        return false;
    }
    if (type != FileTypeJson::PRINTER) {
        qCritical() << "wrong file type" << (uint8_t)type;
        return false;
    }

    qDebug() << "printing: " << templateIdx << br << serial << "...";

    if (!serial.isNull()) {
        if (!openSerial(baudrateMap.value(br), br, serial)) {
            return false;
        }
    }

    int nTry = 50;
    while (!sys_ready4sending()) { // wait max. 5 seconds
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        if (--nTry <= 0) {
            qCritical() << "sys not ready for sending";
            if (!serial.isNull()) {
                closeSerial(serial);
            }
            return false;
        }
    }

    bool ret = true;
    struct T_dynDat dynTicketData;
    memset (&dynTicketData, 0x00, sizeof(dynTicketData));

    // lassen sich auch veraendern
    memcpy(&dynTicketData.licensePlate[0], "WEN1230", 8);
    memcpy(&dynTicketData.vendingPrice[0], "1234", 8);
    memcpy(&dynTicketData.parkingEnd[0], "12:00:00", 8);
    memcpy(&dynTicketData.currentTime[0], "14:15:00", 8);
    memcpy(&dynTicketData.currentDate[0], "01.01.2023", 8);

    for (int i = 0; i < templateIdx.size(); ++i) {
        // dynamische Daten werden gespeichert
        if (prn_sendDynamicPrnValues(&dynTicketData.licensePlate[0])) {
            // angabe welches template beim drucken benutzt werden soll
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            if (prn_printTemplate(templateIdx[i])) {
                qDebug() << "printing template" << templateIdx[i];
                std::this_thread::sleep_for(std::chrono::seconds(3));
            }
        } else {
            ret = false;
            continue;
        }
    }
    if (!serial.isNull()) {
        closeSerial(serial);
    }
    return ret;

}

// ------------------------------------------------------------------------------
// Level 1, control device-controller (functions of µC)
// check serial connection to deviceController
// read response from DC2 (input data)
// some test function for serial communication
// also Bootloader is here
// ------------------------------------------------------------------------------

void hwapi::dc_requTestResponse() const
{
    sendWRcmd_setSendCommand0(SENDDIRCMD_TestSerial);
}

bool hwapi::dc_readAnswTestResponse() const
{
    return epi_getResult_serialTestOK();
}

uint8_t hwapi::dc_isRequestDone(void) const
{
    // retval:  0: request is still in progress
    //          1: answer from DC2 was OK
    //          2: wrong answer from DC2
    return epi_getResultOfLastRequest();
}

uint16_t hwapi::dc_getCompletePayLoad(uint16_t plBufSiz, uint8_t *payLoad) const
{
    // get data back in *pl, max 64 byte, can be used for diagnosis
    // retval = nr of bytes received. If host buffer too small then
    // only plBufSíz bytes are copied to pl
    // plBufSíz=size of host buffer

    return epi_getLastPayLoad( plBufSiz,  payLoad);

}

void hwapi::dc_setWakeFrequency(uint8_t period) const
{
    // RTC wakes DC2 (and PTU) by hardware signal every 32seconds
    // change wake signal period to 1...64s
    sendWRcmd_setSendCommand4(SENDDIRCMD_setWakeFrequ, period,0,0,0);
}

void hwapi::dc_OrderToReset(void) const
{
    uint8_t len, buf[160];

    len=dcBL_restartDC(buf);
    sendWRcmd_setSendBlock160(len, buf);
    //sendWRcmd_setSendCommand0(SENDDIRCMD_MakeReset);
    // not needed, sendWRcmd_setSendBlock160() starts sending as well...
}

QString hwapi::dc_getSerialState(void) const
{
// geht
    return epi_getTxt4comStateLine();
}

void hwapi::dc_clrSerialStateText(void) const
{
    epi_clrTxt4comStateLine();
}



void hwapi::bl_sendDataDirectly(uint8_t length, uint8_t *buf) const
{
    // send without protocol frame, needed for the DC bootloader
    sendWRcmd_setSendBlock160(length, buf);

}

uint8_t hwapi::getRawRecLength(void) const
{
    return epi_getRawRecLength();
}

uint8_t hwapi::getRawReceivedData(uint8_t *receivedData) const
{
    return epi_getRawReceivedData(receivedData);
}




QString hwapi::dc_getSerialParams(void) const
{
    return epi_getSlaveParamSTR();
}

QString hwapi::dc_getHWversion(void) const
{
    return epi_loadGenerals(0);
}

QString hwapi::dc_getSWversion(void) const
{
    return epi_loadGenerals(1);
}

QString hwapi::dc_getState(void) const
{
    return epi_loadGenerals(2);
}


// ------------------------------------------------------------------------------
// Level 2  DC2-onboard devices
//          WR: set time
//          RD. get time, get measure, get test results
// ------------------------------------------------------------------------------

// get UID, get time/date   test results   memory,  RTC  analog values

// ----------------------------------------------------------------------------------------------------------
// Date and Time
// ----------------------------------------------------------------------------------------------------------

uint8_t hwapi::rtc_getDateTime(struct Trtc_DateTime *rtc_DateTime) const
{
//    void epi_getTime(uint8_t *hh, uint8_t *mm, uint8_t *ss);
//    void epi_getDate(uint8_t *yy, uint8_t *mm, uint8_t *dd);
//    void epi_getToday(uint8_t *dow, uint16_t *minOfToday, uint32_t *secOfToday);
    uint8_t H, M, S;
    uint16_t unused16;
    uint32_t unused32;

    epi_getTime(&H, &M, &S);
    rtc_DateTime->rtc_hour=H;
    rtc_DateTime->rtc_min=M;
    rtc_DateTime->rtc_sec=S;

    epi_getDate(&H, &M, &S);
    rtc_DateTime->rtc_year=H;
    rtc_DateTime->rtc_month=M;
    rtc_DateTime->rtc_dayOfMonth=S;

    epi_getToday(&H, &unused16, &unused32);
    rtc_DateTime->rtc_dayOfWeek=H;
    return 0;
}

uint8_t hwapi::rtc_setDateTime(void) const
{
    sendWRcmd_setSendCommand0(SENDDIRCMD_setTime);
    return 0;
}


void hwapi::rtc_getTime(uint8_t *hh, uint8_t *mm, uint8_t *ss) const
{
    epi_getTime(hh, mm, ss);
}

void hwapi::rtc_getDate(uint8_t *yy, uint8_t *mm, uint8_t *dd) const
{
    epi_getDate(yy, mm, dd);
}

uint8_t hwapi::rtc_getToday(uint8_t *dow, uint16_t *minOfToday, uint32_t *secOfToday) const
{
    // dow=day of week, 1=monday...7
    // minOfToday: 0=midnight...1439= 23:59
    // secOfToday: 0=midnight...86399= 23:59:59

    epi_getToday(dow, minOfToday, secOfToday);
    return 0;
}

bool hwapi::rtc_isLeapYear(uint8_t *lastLeapYear, uint8_t *NextLeapYear) const
{
    return epi_isLeapYear(lastLeapYear, NextLeapYear);
}


bool hwapi::rtc_isLeapYear(void) const
{
    return epi_isLeapYear();
}

void hwapi::rtc_getWeek(uint8_t *DayOfWeek, uint8_t *HoursOfWeek, uint16_t *MinutesOfWeek) const
{
    epi_getSpecialWeekTimeDate(DayOfWeek, HoursOfWeek, MinutesOfWeek);
}

void hwapi::rtc_getMonth(uint8_t *DayOfMonth, uint16_t *HoursOfMonth, uint16_t *MinutesOfMonth) const
{
    epi_getSpecialMonthTimeDate(DayOfMonth, HoursOfMonth, MinutesOfMonth);
}

void hwapi::rtc_getYear(uint16_t *DayOfYear, uint16_t *HoursOfYear, uint32_t *MinutesOfYear) const
{
    epi_getSpecialYearTimeDate(DayOfYear, HoursOfYear, MinutesOfYear);
}


QString hwapi::rtc_getTimStr() const
{
    uint8_t hh,  mm,  ss, buf[20], nn;
    QString qbuf;
    char ctmp;
    qbuf.clear();
    for (nn=0; nn<20; nn++) buf[nn]=0;
    epi_getTime(&hh, &mm, &ss);
    GetTimeString(hh, mm, ss, HourSys24h, MITSEK, buf); // about 12byte long
    for (nn=0; nn<20; nn++)
    {
        ctmp=buf[nn];
        qbuf[nn]=ctmp;
    }
    return qbuf;
}

QString hwapi::rtc_getDatStr() const
{
    uint8_t day,  month,  year, buf[20], nn;
    QString qbuf;
    char ctmp;

    qbuf.clear();
    for (nn=0; nn<20; nn++) buf[nn]=0;
    epi_getDate(&year, &month, &day);
    GetDateString(day, month, 0x20, year, DateFormatDeutsch, 0, buf);
    for (nn=0; nn<20; nn++)
    {
        ctmp=  buf[nn];
        qbuf[nn]=ctmp;
    }
    return qbuf;
}

QString hwapi::rtc_getTimDatStr() const
{
    // style: 0: hh:mm    1: hh:mm:ss
    QString qbuf;

    qbuf.clear();
    qbuf.append(rtc_getTimStr());
    qbuf.append("   ");
    qbuf.append(rtc_getDatStr());
    return qbuf;
}





// UID
void hwapi::dc_getUID8byte(uint8_t *buf8byteUid) const
{
    epi_getUIDdec(buf8byteUid);
}

QString hwapi::dc_getUIDstr() const
{
    return epi_getUIDstr();
}

uint64_t hwapi::dc_getUIDnumber(void) const
{
    uint64_t retval=0;
    uint8_t buf8byteUid[12], nn;

    epi_getUIDdec(buf8byteUid);
    for (nn=8; nn>0; nn--)
    {
        retval+=buf8byteUid[nn-1];
        retval<<=8;     // *256
    }
    return retval;
}



uint32_t hwapi::dc_getTemperature(void) const
{
    //
    return epi_loadMeasureValue(MEASCHAN_TEMPERATURE);
}

QString hwapi::dc_getTemperaturStr(void) const
{
    return epi_getSlaveTemperatureStr();
}


uint32_t hwapi::dc_getVoltage(void) const
{
    // in mV, e.g. 12300 = 12,3V
    return epi_loadMeasureValue(MEASCHAN_VOLTAGE);
}

QString hwapi::dc_getVoltagStr(void) const
{
    return epi_getSlaveVoltageStr();
}

bool hwapi::dc_mainFuseIsOk(void) const
{
    uint32_t ulong=epi_loadMeasureValue(MEASCHAN_VOLTAGE); // in mV, e.g. 12300 = 12,3V
    if (ulong>3000)
        return true;
    return false;
}

// ------------------------------------------------------------------------------
// Level 3: digital outputs and simple switching of connected devices
//          simple processes like flashing a led or open flap for 1s
// ------------------------------------------------------------------------------

// Locks:
uint8_t hwapi::lock_switchUpperLock(uint8_t dir) const
{
    // dir 0=off 1=up 2=down
    sendWRcmd_setSendCommand4(SENDDIRCMD_MOVEUP_LOCK ,dir,0,0,0);
    return 0;
}

uint8_t hwapi::lock_switchLowerLock(uint8_t dir) const
{
    // dir 0=off 1=up 2=down
    sendWRcmd_setSendCommand4(SENDDIRCMD_MOVEDN_LOCK ,dir,0,0,0);
    return 0;
}

void hwapi::lock_switchVaultDoor(void) const
{

    sendWRcmd_setSendCommand0(SENDDIR_OPENVAULT);
}

void hwapi::coin_switchRejectMotor(uint8_t dir) const
{

    sendWRcmd_setSendCommand4(SENDDIR_REJMOT_ON, dir, 0,0,0);
}

void hwapi::coin_rejectCoins(void) const
{

    sendWRcmd_setSendCommand0(SENDDIR_REJMOT_RUN);
}


void hwapi::led_switchLedService(uint8_t on) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_LEDINSIDE, on, 0, 0, 0);
}

void hwapi::led_switchLedPaper(uint8_t on, uint8_t ton, uint8_t tof) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_LEDTICKET, on, ton, tof, 0);
}

void hwapi::led_switchLedPinPad(uint8_t on, uint8_t ton, uint8_t tof) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_LEDPAD, on, ton, tof, 0);
}

void hwapi::led_switchLedStart(uint8_t on, uint8_t ton, uint8_t tof) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_LEDSTART, on, ton, tof, 0);
}

void hwapi::led_switchLedCoinbassin(uint8_t on, uint8_t ton, uint8_t tof) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_LEDCOIN, on, ton, tof, 0);
}

void hwapi::fan_switchFan(bool on) const
{
    //return epi_storeDOsToSend(DOBYTE3, FAN_ON, on);
    sendWRcmd_setSendCommand4(SENDDIRCMD_FAN, on, 0, 0, 0);
}

void hwapi::alarm_switchSiren(bool on) const
{
    //return epi_storeDOsToSend(DOBYTE4, LAERM, on);
    sendWRcmd_setSendCommand4(SENDDIRCMD_LAERM, on, 0, 0, 0);
}

void hwapi::bar_OpenBarrier(bool open) const
{
    //return epi_storeDOsToSend(DOBYTE4, REL1, open);
    sendWRcmd_setSendCommand4(SENDDIRCMD_REL1, open, 0, 0, 0);
}

void hwapi::ptu_switchWake(bool WAKEACTIVE) const
{
    //return epi_storeDOsToSend(DOBYTE1, CTS_PTU, WAKEACTIVE);
    sendWRcmd_setSendCommand4(SENDDIRCMD_WAKEPTU, WAKEACTIVE,0,0,0);
}

// AUX-IO's or barcode reader
void hwapi::aux_power(bool on) const
{
//    return epi_storeDOsToSend(DOBYTE2, BARC_POW_ON, on);
    sendWRcmd_setSendCommand4(SENDDIRCMD_AUXPWR, on,0,0,0);
}

void hwapi::aux_setUsage(uint8_t PinDirection) const
{
    // bit 0= Aux1    bit5=Aux6  1=output  0=input with pullup

    //    return epi_storeDOsToSend(DOBYTE6, nr, PinDirection);
    sendWRcmd_setSendCommand4(SENDDIRCMD_AUXDDR, PinDirection,0,0,0);
}

void hwapi::aux_setOutputs(uint8_t PinIsHigh) const
{
    // PinIsHigh bit 0..5 =Aux1...6  1=output high  0=set output low

    //return epi_storeDOsToSend(DOBYTE5, nr, PinIsHigh);
    sendWRcmd_setSendCommand4(SENDDIRCMD_AUXOUT, PinIsHigh,0,0,0);
}

void hwapi::lock_switchContactPower(bool on) const
{
    //epi_storeDOsToSend(DOBYTE2, U_SW_ON, on);
    sendWRcmd_setSendCommand4(SENDDIRCMD_UCONTACT_ON, on, 0,0,0);
}

void hwapi::prn_switchPower(bool on) const
{
    // also switches and enables serial driver
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN2_SWONOFF, on,0,0,0);
    indat_storePrinterPower(on);
    // PRINTER-ON/OFF zusätzlich statisch abspeichern
    //       Status-request soll nur gesendet werden wenn der Drucker ein ist
    //       Status-Abfrage (hier in HWapi) gibt 0 zurück wenn power-off
    // dito mit allen anderen Geräten!

    // pi ---> storeINdata.cpp  speichert diese statische Info (printer on/off) UND
    // auch alles rückgelesene

}


void hwapi::mif_readerOn(bool on) const
{
    // DC2 also switches and enables serial driver
    sendWRcmd_setSendCommand4(SENDDIRCMD_MIF_SWONOFF, on,0,0,0);
}

void hwapi::mif_creatAtbCard(uint8_t cardType) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MIF_SWONOFF, cardType, 0,0,0);
}


void hwapi::mod_switchPower(bool on) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MOD_SWONOFF, on,0,0,0);
}

void hwapi::mod_switchWake(bool WAKEACTIVE) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MOD_WAKE, WAKEACTIVE,0,0,0);
}

void hwapi::mdb_switchPower(bool on) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_POWER, on,0,0,0);   
}

void hwapi::mdb_switchWake(bool WAKEACTIVE) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_WAKE, WAKEACTIVE,0,0,0);
}

void hwapi::credit_switchPower(bool on) const
{    
    sendWRcmd_setSendCommand4(SENDDIRCMD_CRED_ON, on,0,0,0);
}

void hwapi::credit_switchWake(bool WAKEACTIVE) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_CRED_WAKE, WAKEACTIVE,0,0,0);
}

void hwapi::shut_move(bool open) const
{
    // true:open  false:close
    sendWRcmd_setSendCommand4(SENDDIRCMD_SHUT_MOV, open, 0,0,0);
}

void hwapi::esc_moveFlaps(uint8_t flap ) const
{
    // 0: close both  1: open take-flap   2: open return
    sendWRcmd_setSendCommand4(SENDDIRCMD_ESCRO_MOV, flap, 0,0,0);
}


// ------------------------------------------------------------------------------
// Level 3: digital inputs of connected devices
// ------------------------------------------------------------------------------



uint8_t hwapi::door_getSwitches(void) const
{
    // retval         // bit0: upper door  1: low door  2:vault door
    uint8_t ret;

    ret= epi_getDI_doorSwitches();
        // bit0: upper door  1: low door  2:vault door
    ret &= 0x08;
    return ret;
}

bool    hwapi::door_isUpperDoorOpen(void) const
{
    uint8_t ret;

    ret= epi_getDI_doorSwitches();
        // bit0: upper door  1: low door  2:vault door
    if (ret &  1)
        return true;
    return false;
}

bool    hwapi::door_isLowerDoorOpen(void) const
{
    uint8_t ret;

    ret= epi_getDI_doorSwitches();
        // bit0: upper door  1: low door  2:vault door
    if (ret &  2)
        return true;
    return false;
}

bool    hwapi::vault_isVaultDoorOpen(void) const
{
    uint8_t ret;

    ret= epi_getDI_doorSwitches();
        // bit0: upper door  1: low door  2:vault door
    if (ret &  4)
        return true;
    return false;
}


uint8_t hwapi::vault_getSwitches(void) const
{
    // retval bit0: cash box,  bit 1: bill box
    uint8_t ret;

    ret=epi_getDI_vaultSwitches();      // bit0: cash box    1: bill box in
    ret&=0x03;
    return ret;
}

bool hwapi::vault_isCoinVaultIn(void) const
{
    uint8_t ret;

    ret=epi_getDI_vaultSwitches();      // bit0: cash box    1: bill box in
    if (ret & 1)
        return true;
    return false;
}

bool hwapi::vault_isBillVaultIn(void) const
{
    uint8_t ret;

    ret=epi_getDI_vaultSwitches();      // bit0: cash box    1: bill box in
    if (ret & 2)
        return true;
    return false;
}



uint8_t hwapi::door_getLocks(void) const
{
    // retval bit0: upper lever is up
    //        bit1: upper lever is down
    //        bit2: lower lever is up
    //        bit3: lower lever is down

    uint8_t ret;

    ret= epi_getDI_lockSwitches();
        // retval: bit 0: upper lockbar up   bit1: upper lockbar is down
        //         bit 2: lower lockbar up   bit1: lower lockbar is down
    ret&=0x0F;
    return ret;
}

bool hwapi::door_upperDoorIsLocked(void) const
{
    uint8_t ret;

    ret= epi_getDI_lockSwitches();
    if (ret & 2)
        return true;
    return false;
}

bool hwapi::door_upperDoorIsUnlocked(void) const
{
    uint8_t ret;

    ret= epi_getDI_lockSwitches();
    if (ret & 1)
        return true;
    return false;
}

bool hwapi::door_lowerDoorIsLocked(void) const
{
    uint8_t ret;

    ret= epi_getDI_lockSwitches();
    if (ret & 8)
        return true;
    return false;
}

bool hwapi::door_lowerDoorIsUnlocked(void) const
{
    uint8_t ret;

    ret= epi_getDI_lockSwitches();
    if (ret & 4)
        return true;
    return false;
}



bool    hwapi::bar_optoIn1isOn(void) const
{
    uint8_t ret=epi_getDI_optos();
        // bit0: opto in 1    1: opto in 2
    if (ret & 1)
        return true;
    return false;
}

bool    hwapi::bar_optoIn2isOn(void) const
{
    uint8_t ret=epi_getDI_optos();
        // bit0: opto in 1    1: opto in 2
    if (ret & 2)
        return true;
    return false;
}


uint8_t hwapi::aux_getAuxInputs(void) const
{
    // retval: bit0=Aux1....Bit5=Aux6
    //          0: input low  1:input high

    uint8_t ret=epi_getDI_auxIn();
    // bit0: auxin 1  ...  5: auxin 6
    ret &=0x3F;
    return ret;
}

bool hwapi::ptu_WakeINisActive(void) const
{
    return epi_getDI_ptuWake();
}

bool hwapi::mdb_WakeINisActive(void) const
{
    return epi_getDI_mdbWake();
}

bool hwapi::prn_readyINisActive(void) const
{
    return epi_getDI_prnReady();
}

bool hwapi::coid_isAttached(void) const
{
    return epi_getDI_CoinAttach();
}

bool hwapi::coin_escrowIsOpen(void) const
{
    return epi_getDI_CoinEscrow();
}

bool hwapi::mif_cardIsAttached(void) const
{
    return epi_getDI_mifareCardTapped();
}

//bool hwapi::mod_WakeINisActive(void)
//{
//    return epi_getDI_modemWake();
//}



bool hwapi::door_isContactPowerOn(void) const
{
    return  epi_getDI_contactPwr();
}

bool hwapi::mif_isMifarePowerOn(void) const
{
    bool mo=indat_isMifareOn();
    bool mi=epi_getDI_mifarePwr();
    if (mo && mi)
        return true;
    return false;
}

bool hwapi::mdb_testIsmdbTxDon(void) const
{
    return  epi_getDI_mdbTxd();
}

bool hwapi::aux_isAuxPowerOn(void) const
{
    return  epi_getDI_auxPwr();
}

bool hwapi::mod_isGsmPowerOn(void) const
{
    return  epi_getDI_gsmPwr();
}

bool hwapi::cred_isCreditPowerOn(void) const
{
    return  epi_getDI_creditPwr();
}

bool hwapi::prn_isPrinterPowerOn(void) const
{
    return  epi_getDI_printerPwr();
}

uint8_t hwapi::prn_PrnFuseIsOk(void) const
{
    //retval:  0: fuse blown   1: fuse OK   2:unknown as printer power is off
    if (!epi_getDO_printerPwr())
        return 2;       // unknown as printer power is off
    if (epi_getDI_printerPwr())
        return 1;       // printer voltage is OK
    return 0;       // fuse blown
}

bool hwapi::mdb_isMdbPowerOn(void) const
{
    return  epi_getDI_mdbPwr();
}


bool hwapi::cash_getRejectMotorHomePos(void) const
{
    return epi_getDI_rejectMotor_homepos();
}

uint8_t hwapi::cash_getLowPaperSensor(void) const
{
    // 0: Sensor sees paper 1: no paper 99: off
    return  epi_getDI_npe_sensor();

}

// ------------------------------------------------------------------------------
// Level1,2,3     RD request commands
// ------------------------------------------------------------------------------

// the following requests can be sent manually
//   or automatically in background by:   void hwapi::dc_autoRequest(bool on)
//   in other words:
//   if automatic-reading is on then there's no need to send any of these commands!


void hwapi::request_DC2serialConfig() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_SERCONF);
}

void hwapi::request_DC2_HWversion() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_HWversion);
}

void hwapi::request_DC2_SWversion() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_SWversion);
}

void hwapi::request_DC2_condition() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_CONDITION);
}

void hwapi::request_DC2_UID() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_UID);
}

void hwapi::request_DC2_TimeAndDate() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_TIME);
}

void hwapi::request_DC2_analogues() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_ANALOGS);
}

void hwapi::request_DC2_digitalInputs() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_DIG_INPUTS);
}

void hwapi::request_DC2_digitalOutputs() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_DIG_OUTPUTS);
}

// ------------------------------------------------------------------------------
// the folowing device state requests are deployed only if device is powered up:

void hwapi::request_PrinterHwState() const
{

    sendWRcmd_setSendCommand0(SEND_REQU_PRN_STATE);
}

void hwapi::request_PrinterCurrentFonts() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_PRN_FONTS);
}

void hwapi::request_PrinterStateComplete() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_PRN_ALL);
}





void hwapi::request_MifareReaderState() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_MIFSTATE);
}

void hwapi::request_MifareCardType() const
{
    //uint8_t blkAdr=0;
    //sendWRcmd_setSendCommand4(SEND_REQU_MIFDATA, blkAdr,0,0,0);
    sendWRcmd_setSendCommand0(SEND_REQU_MIFSTATE);
}

void hwapi::request_MifareAtbType() const
{
    //sendWRcmd_setSendCommand0(SEND_REQU_MIF_ATB_TYPE);
    sendWRcmd_setSendCommand0(SEND_REQU_MIFSTATE);

}

void hwapi::request_MifareID() const
{
    uint8_t sequenceNumber=0;
    sendWRcmd_setSendCommand4(SEND_REQU_MIFDATA, sequenceNumber,0,0,0); // 1st data = card sequence =blk nr (0...15)
}

void hwapi::request_MifareData(uint8_t dataBlockNumber) const
{   
    if (dataBlockNumber<12)     // 1k cards return 12 data blocks, 4k cards would return 54 data blocks (not implemented)
        sendWRcmd_setSendCommand4(SEND_REQU_MIFDATA, dataBlockNumber,0,0,0); // 1st data = card sequence =blk nr (0...15)
}



void hwapi::request_MDB_Status() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_MDB_GETSTAT);
}

//void hwapi::request_MDB_wakeInLine() const
//{
//    sendWRcmd_setSendCommand0(SEND_REQU_MDB_GETWAK);
//}

void hwapi::request_MDB_lastResponse() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_MDB_GETRESP);
}

void hwapi::request_EMP_allParameters() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_EMP_GETALL);
}

void hwapi::request_EMP_lastCoin() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_EMP_GETCOIN);

}



// ------------------------------------------------------------------------------
// Level 3: readback digital outputs of connected devices
//          these functions are not needed for normal operation
//          but can be used to test and verify conditions

//          There are two options:
//              1) the important things like power-outputs and wake lines are
//              measured at DC2-terminals (after transistors) and come as input to DC-board
//              2) others like Leds are read from µC-pins by DC-board
// ------------------------------------------------------------------------------

bool hwapi::test_getDO_mdbRXtst(void) const
{
    return  epi_getDO_mdbRxTestOut();
}

uint8_t hwapi::lock_getDO_motors(void) const
{
    // bit0: upper lock forward    bit 1 backward
    // bit2: lower lock forward    bit 3 backward

    return epi_getDO_motorOuts();
}

uint8_t hwapi::test_serialState(void) const
{
    // test on-board signals for the serials
    // serial drv on/off, Serial mux1, Serial mux2

    uint8_t ret=epi_getDO_serialSwitch();
        // serial drv on/off, Serial mux1, Serial mux2
    ret &=0x07;
    return ret;
}

bool hwapi::test_serialIsOn(void) const
{
    return epi_getDO_serialDriverIsOn();
}

bool hwapi::test_serialMux1isSetToPrinter(void) const
{
    return epi_getDO_serialMux1isSetToPrinter();
    // mux1 off: serial is switched to printer
}

bool hwapi::test_serialMux1isSetToModem(void) const
{
    return  epi_getDO_serialMux1isSetToModem();
    // mux1 on: serial is switched to modem
}

bool hwapi::test_serialMux2isSetToCredit(void) const
{
    return epi_getDO_serialMux2isSetToCredit();
    // mux2 off: serial is switched to credit card terminal
}

bool hwapi::test_serialMux2isSetToMifare(void) const
{
    return epi_getDO_serialMux2isSetToMifare();
    // mux2 on: serial is switched to mifare reader
}

bool hwapi::led_coinIsOn(void) const
{
    return epi_getDO_led_coin();
}

bool hwapi::led_frontIsOn(void) const
{
    return epi_getDO_led_front();
}

bool hwapi::led_ticketIsOn(void) const
{
    return epi_getDO_led_ticket();
}

bool hwapi::led_pinIsOn(void) const
{
    return epi_getDO_led_pin();
}

bool hwapi::led_StartIsOn(void) const
{
    return epi_getDO_led_start();
}

bool hwapi::led_insideIsOn(void) const
{
    return epi_getDO_led_inside();
}

bool hwapi::fan_isOn(void) const
{
    return epi_getDO_fan();
}

bool hwapi::siren_isOn(void) const
{
    return epi_getDO_sirene();
}

bool hwapi::bar_relayIsOn(void) const
{
    return epi_getDO_relay();
}

bool hwapi::ptu_WakeOutIsOn(void) const
{
    return epi_getDO_ptuWake();
}

bool hwapi::aux_powerIsOn(void) const
{
    return epi_getDO_auxPower();
}


bool hwapi::coin_shutterIsOpen(void) const
{
    return epi_getDO_coinShutterOpen();
}

bool hwapi::coin_shutterTestOutput(void) const
{
    return epi_getDO_coinShutterTest();
}

uint8_t hwapi::coin_escrowFlapOpened(void) const
{
    // retval: 1:return flap is open   2:take flap is open    0:closed

    return epi_getDO_coinEscrow();
}



void hwapi::sendDeviceSettings(uint8_t kindOfPrinter, uint8_t kindOfCoinChecker,
                               uint8_t kindOfMifareReader, uint8_t suppressSleep,
                               uint8_t kindOfModem, uint8_t kindOfCredit) const
{
    uint8_t buf[64];

    tslib_strclr(buf,0,64);
    buf[0]=kindOfPrinter;
    buf[1]=kindOfCoinChecker;
    buf[2]=kindOfMifareReader;
    buf[3]=suppressSleep;
    buf[4]=kindOfModem;
    buf[5]=kindOfCredit;

    epi_store64ByteSendData(6, buf);
    sendWRcmd_setSendCommand0(SENDDIRCMD_DEVICE_PARA);


}

void hwapi::request_ReadbackDeviceSettings() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_DEVICE_PARA);
}


void hwapi::readback_DeviceSettings(uint8_t *length, uint8_t *data) const
{

    epi_restoreRbDeviceSettings(length, data);
/*
            buf66[0]=devPara.kindOfPrinter;
            buf66[1]=devPara.kindOfCoinChecker;
            buf66[2]=devPara.kindOfMifareReader;
            buf66[3]=devPara.suppressSleepMode;
            buf66[4]=devPara.kindOfModem;
            buf66[5]=devPara.kindOfCreditcard;
            buf66[6]=devPara.CoinEscrow;
            buf66[7]=devPara.CoinRejectUnit;
            buf66[8]=devPara.CoinShutter;
            buf66[9]=devPara.BillAcceptor;
            buf66[10]=devPara.usevaultLock;
            buf66[11]=devPara.autoAlarm;
            buf66[12]=devPara.autoOpen;
            buf66[13]=devPara.printAccReceipt;
            buf66[14]=devPara.printDoorReceipt;
            buf66[15]=devPara.printTokenTicket;
            uitmp=devPara.VaultFullWarnLevel;
            buf66[16]=swl_getOneByteFromUint(uitmp, GETLOWBYT);
            buf66[17]=swl_getOneByteFromUint(uitmp, GETHIGHBYT);
            uitmp=devPara.VaultFullErrorLevel;
            buf66[18]=swl_getOneByteFromUint(uitmp, GETLOWBYT);
            buf66[19]=swl_getOneByteFromUint(uitmp, GETHIGHBYT);

*/
}

// ....................................................................................

void hwapi::sendMachineID(uint16_t customerNr, uint16_t machineNr,
                          uint16_t borough, uint16_t zone,
                          uint16_t alias,   char *location) const
{
    uint8_t buf[64];

    tslib_strclr(buf,0,64);
    buf[0]=uint2uchar(customerNr, LOWBYTE);
    buf[1]=uint2uchar(customerNr, HIGHBYTE);
    buf[2]=uint2uchar(machineNr, LOWBYTE);
    buf[3]=uint2uchar(machineNr, HIGHBYTE);
    buf[4]=uint2uchar(borough, LOWBYTE);
    buf[5]=uint2uchar(borough, HIGHBYTE);
    buf[6]=uint2uchar(zone, LOWBYTE);
    buf[7]=uint2uchar(zone, HIGHBYTE);
    buf[8]=uint2uchar(alias, LOWBYTE);
    buf[9]=uint2uchar(alias, HIGHBYTE);
    tslib_strcpy(location, &buf[10], 32);

    epi_store64ByteSendData(42, buf);
    sendWRcmd_setSendCommand0(SENDDIRCMD_MACHINE_ID);


}

void hwapi::request_ReadbackMachineID() const
{
    sendWRcmd_setSendCommand0(SEND_REQU_MACINE_ID);
}


void hwapi::readback_machineIDdata(uint8_t *length, uint8_t *data) const
{
    epi_restoreMachineIDsettings(length, data);
/*
            buf66[0]=swl_getOneByteFromUint(machPara.customerNumber, GETLOWBYT);
            buf66[1]=swl_getOneByteFromUint(machPara.customerNumber, GETHIGHBYT);
            buf66[2]=swl_getOneByteFromUint(machPara.machineNumber, GETLOWBYT);
            buf66[3]=swl_getOneByteFromUint(machPara.machineNumber, GETHIGHBYT);
            buf66[4]=swl_getOneByteFromUint(machPara.borough, GETLOWBYT);
            buf66[5]=swl_getOneByteFromUint(machPara.borough, GETHIGHBYT);
            buf66[6]=swl_getOneByteFromUint(machPara.zone, GETLOWBYT);
            buf66[7]=swl_getOneByteFromUint(machPara.zone, GETHIGHBYT);
            buf66[8]=swl_getOneByteFromUint(machPara.alias, GETLOWBYT);
            buf66[9]=swl_getOneByteFromUint(machPara.alias, GETHIGHBYT);
            for (pp=0; pp<32; pp++)
                buf66[10+pp]=machPara.location[pp];
            dc2prot_setReadData(42, buf66);

*/
}


// ....................................................................................





static uint16_t hwapi_shutterTime;

// locks, 2.Level: (Motor stops automatical on end switch or by 5s timeout)
uint8_t hwapi::lock_openUpperDoor(void) const
{
    //bool sendWRcmd_setSendCommand4(uint16_t nextCmd, uint8_t dat1, uint8_t dat2, uint8_t dat3, uint8_t dat4);
        // commands are defined in PIdefines.h
    sendWRcmd_setSendCommand4(SENDDIRCMD_OPENUP_DOOR, 1, 0, 0, 0);
        // paras:   dat2: 1=upper door lock   2=lower
        //          dat1: 1=open              2=close
    return 0;
}


uint8_t hwapi::lock_closeUpperDoor(void) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_OPENUP_DOOR, 2, 0, 0, 0);
    return 0;
}

uint8_t hwapi::lock_openLowerDoor(void) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_OPENDN_DOOR, 1, 0, 0, 0);
    return 0;
}

uint8_t hwapi::lock_closeLowerDoor(void) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_OPENDN_DOOR, 2, 0, 0, 0);
    return 0;
}

void hwapi::shut_openOnce(void) const
{
    // and close automatic after shutter time
    uint16_t zeit=hwapi_shutterTime;
    zeit/=100;
    sendWRcmd_setSendCommand4(SENDDIRCMD_SHUTOPENBYTIME, uint8_t(zeit) ,0,0,0);

}

void hwapi::shut_openForCoin(bool start) const
{
    // start=true: start opening flap if coin is attached
    // start=false: stop process

    uint16_t zeit=hwapi_shutterTime;
    zeit/=100;
    sendWRcmd_setSendCommand4(SENDDIRCMD_SHUTOPENBYCOIN, uint8_t(start), uint8_t(zeit),0,0);

}

void hwapi::shut_sendOpeningTime(uint16_t timeIn_ms ) const
{
    // after this time without retrigger the flap is closed
    //sendWRcmd_setSendCommand4(SENDDIRCMD_SHUT_SENDTIME, timeIn100ms,0,0,0);
    hwapi_shutterTime=timeIn_ms;

}


void hwapi::esc_takeMoney(void) const
{
    // and close automatically after escrow time (1s)
    sendWRcmd_setSendCommand0(SENDDIRCMD_ESCRO_TAKE);
}

void hwapi::esc_returnMoney(void) const
{
    // and close automatically after time
    sendWRcmd_setSendCommand0(SENDDIRCMD_ESCRO_GIVE);

}







// ----------------------------------------------------------------------------------------------------------
// --------------------------------------------- MIFARE -----------------------------------------------------
// ----------------------------------------------------------------------------------------------------------


uint8_t hwapi::mif_returnReaderStateAndCardType(uint8_t *buf, uint8_t maxBufferSize) const
{
    // retval 0=OK 1=error host buffer too small

    /* data description:

    new fast version:
    byte 0= still the same: current read state:
                                0=power off  1=reader-fault 2=ready
                                3=just reading 4=read complete
                                5=read partial, removed too early
                                6=state unknown

    byte 1: reader state 1=ok 0=nok
    byte 2: card present (0,1)
    byte 3: card selected (0)
    byte 4: card type: 0...5
    byte 5: card allowed (0=no  1=MifareClassic 1k or 4k)
    byte 6: CardSize: 1 or 4 (kB)
    byte 7: length of UID 4 or 7 (byte)
    */

    return epi_restoreMifState(buf, maxBufferSize);
}

/* OLD data description:
byte 0: current read state: 0=power off  1=reader-fault 2=ready
                            3=just reading 4=read complete
                            5=read partial, removed too early
                            6=state unknown
byte 1,2: read data length from card
3: 1=reader is OK (reported serial nr is OK)  0=wrong or no reader
4...15: reader version, expected "ATB25-1.8"
16: 1=card is present   0:not
17: 0
18: card type reported from reader
19: 1=allowed card type 0=not
20: card size: 1 or 4 (dec) = card size
21: LengthOfUID: 4 or 7 (dec) (byte)
22: UID 8 byte in hex
byte 30: sector logged: 0
byte 31: current sector: 0
byte 32: result, always 0
*/

bool hwapi::mif_readerIsOK(void) const
{

    uint8_t buf[40];    // old version had 40 bytes, new version only 8
    uint8_t ret= epi_restoreMifState(buf, 40);
    if (ret==0 && buf[0]>1 && buf[1]>0)
            return 1;
    return 0;   // error
}

bool hwapi::mif_cardAttached(void) const
{

    uint8_t buf[40];
    uint8_t ret= epi_restoreMifState(buf, 40);
    if (ret==0 && buf[0]>1 && buf[2]>0) // reader OK
        if (buf[16]>0)
            return 1;
    return 0;   // error
}

uint8_t hwapi::mif_readResult(void) const
{
    // result: 0: unknown or still in progress
    //         1: card read successful
    //         2: reading error

    uint8_t buf[40];
    uint8_t ret= epi_restoreMifState(buf, 40);
    // data read successful && Reader OK && card attached && ...
    if (ret==0  && buf[1]>0 && buf[2]>0)
    {
//        byte 0: current read state: 0=power off  1=reader-fault 2=ready
//                                    3=just reading 4=read complete
//                                    5=read partial, removed too early
//                                    6=state unknown

        if (buf[0]==1 || buf[0]==5 || buf[0]==6)
            return 2;
        if (buf[0]==4)
            return 1;

    }
    return 0;   // error

}


QString hwapi::mif_cardUID(void) const
{
    QString myStr;

    uint8_t buf[65], ret;

    //uint8_t ret= epi_restoreMifState(buf, 40);
    myStr.clear();
/*
    if (ret==0 && buf[0]==4 && buf[3]>0 && buf[16]>0 && buf[19]>0)
    {
        // UID in buf[22...29]
        for (int ii=0;ii<8; ii++)
        {

            myStr+=QString::number(buf[ii+22],16);
            myStr+=" ";     // make a gap between numbers
        }
    }
*/

    ret=epi_restoreMifData(0, buf, 64);
    if (ret)
        return myStr;   // return empty string on error
    else
    {
        buf[8]=0;
        //myStr.append(buf);
        for (int ii=0;ii<8; ii++)
        {

            myStr+=QString::number(buf[ii],16); // 16: return in hex format
            myStr+=" ";     // make a gap between numbers
        }

        return myStr;
    }


}


uint8_t hwapi::mif_getCardDataDec(uint8_t blkNr, uint8_t *buf, uint8_t maxBufferSize) const
{
    // blkNr=0...11    return buf[64]   maxBufferSize must be >=64

    return epi_restoreMifData(blkNr, buf, maxBufferSize);
    // blkNr=0...11    return buf[64]

}

QString hwapi::mif_getCardDataStr(uint8_t blockNumber) const
{
    // with blockNumber=0...11
    QString myStr;
    uint8_t buf[66];

    myStr.clear();
    if (blockNumber>11)
        return myStr;

    epi_restoreMifData(blockNumber, buf, 66);

    for (int ii=0; ii<64; ii++)
    {
        //myStr+=QString::number(buf[ii],10);     // decimals as ascii
        myStr+=QString::number(buf[ii],16);     // hex numbers as ascii
        myStr+=" ";     // make a gap between numbers
    }
    return myStr;
}





// ----------------------------------------------------------------------------------------------------------
// --------------------------------------------- PRINTER ----------------------------------------------------
// ----------------------------------------------------------------------------------------------------------

// already above:
// void hwapi::prn_switchPower(bool on)             0x2A01
// bool hwapi::prn_readyINisActive(void)
// bool hwapi::prn_isPrinterPowerOn(void)
// void hwapi::request_PrinterHwState()             0x2A02
// void hwapi::request_PrinterCurrentFonts()        0x2A12
// void hwapi::request_PrinterStateComplete()   // =request_PrinterHwState + request_PrinterCurrentFonts

uint8_t hwapi::prn_getHwState(struct Tprn_hw_state *prn_hw_state) const
{
    // return printer hardware state: power is on? rs-driver on? rs_switch ok? hw-ready-line ok?
    //        printer on error or ok?
    uint8_t prnHWstate[20];

    epi_restorePrinterState(prnHWstate);
        // byte 1...6 come right from printer, see printer manual
        // byte 0 = all important infos:
        // byte 0 = 0: prnter OK,  >0: error
        // bit0: paper low  1: no paper    2: temperature error
        // 3: head open     4: paper jam in cutter
        // 6: no response   7: bad response from printer

    prn_hw_state->powerRdBk = epi_getDI_printerPwr();
    prn_hw_state->rsSwOk    = epi_getDO_serialMux1isSetToPrinter();   // mux1 off: serial is switched to printer
    prn_hw_state->rsDrvOk   = epi_getDO_serialDriverIsOn();
    prn_hw_state->ReadyLine = epi_getDI_prnReady();

    if (prnHWstate[0]==0)
        prn_hw_state->inIdle = true;    // no errors
    else
        prn_hw_state->inIdle = false;    // off or errors

    if (prnHWstate[0] & 1)
        prn_hw_state->paperNearEnd=true;
    else
        prn_hw_state->paperNearEnd = false;

    if (prnHWstate[0] & 2)
        prn_hw_state->noPaper=true;
    else
        prn_hw_state->noPaper = false;

    if (prnHWstate[0] & 4)
        prn_hw_state->ErrorTemp=true;
    else
        prn_hw_state->ErrorTemp = false;

    if (prnHWstate[0] & 8)
        prn_hw_state->HeadOpen=true;
    else
        prn_hw_state->HeadOpen = false;

    if (prnHWstate[0] & 16)
        prn_hw_state->cutterJam=true;
    else
        prn_hw_state->cutterJam = false;


    if (prnHWstate[0] & 64)
        prn_hw_state->noResponse=true;
    else
        prn_hw_state->noResponse = false;

    if (prnHWstate[0] & 128)
        prn_hw_state->badResponse=true;
    else
        prn_hw_state->badResponse = false;
    return prnHWstate[0];

}

bool hwapi::prn_isUpAndReady(void) const
{
    struct Tprn_hw_state prnHwNow;

    prn_getHwState(&prnHwNow);
    if (prnHwNow.inIdle && prnHwNow.rsSwOk && prnHwNow.rsDrvOk && prnHwNow.powerRdBk )
        return true;
    return false;
}

void hwapi::prn_getCurrentFontSetting(struct Tprn_currentSettings *prn_fonts) const
{
    uint8_t prnFonts[22];

    epi_restorePrinterFonts(&prnFonts[0]);
    prn_fonts->currFont  = prnFonts[0];
    prn_fonts->currSize  = prnFonts[1];
    prn_fonts->currHeigth= prnFonts[2];
    prn_fonts->currWidth = prnFonts[3];
    prn_fonts->nowBold   = prnFonts[4];
    prn_fonts->nowInvers = prnFonts[5];
    prn_fonts->nowUnderlined= prnFonts[6];
    prn_fonts->currDensity  = prnFonts[7];
    prn_fonts->currSpeed    = prnFonts[8];
    prn_fonts->nowAligned   = prnFonts[9];

}


void hwapi::prn_sendText(QByteArray *buf) const
{
    sub_storeSendingText(buf);
    epi_storeUserOfSendingTextBuffer(1,0,0,0,0);  // 1=print text


}


void hwapi::prn_sendPrnSysCmd(uint8_t para1, uint8_t para2, uint32_t para3) const
{
    // send three byte through to printer, see printers manual
    sendWRcmd_setSendCommand8(SENDDIRCMD_PRN_SYS_CMD, para1, para2, 0, para3);
}

void hwapi::prn_sendPrnEscCmd(uint8_t para1, uint8_t para2, uint8_t para3, uint8_t para4) const
{
    // send four byte through to printer, see printers manual
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_ESC_CMD, para1, para2, para3, para4);
}

void hwapi::prn_sendPrnSetup(uint16_t paperSpeed, uint8_t density,  uint8_t alignment, uint8_t orientation) const
{
    // send 5 byte: byte 0,1: speed  5...250 mm/s
    //              byte2: density   0....(25)....50
    //              byte3: alignment    'l', 'c', 'r' = left, center, right
    //              byte4: orientation  0, 90, 180    = 0°, 90°, 180° rotation (by now not supported!)
    // not batched! don't use twice within 100ms

    uint8_t buf[10];
    uint16_t uitmp;

    uitmp=paperSpeed;
    buf[0]=uint8_t(uitmp);
    uitmp>>=8;
    buf[1]=uint8_t(uitmp);
    buf[2]=density;
    buf[3]=alignment;
    buf[4]=orientation;
    buf[5]=0;
    epi_store64ByteSendData(5, buf);
    sendWRcmd_setSendCommand0(SENDDIRCMD_PRN_SETUP);
}

void hwapi::prn_movePaper(uint8_t wayInMm, uint8_t direction) const
{
    //direction: 1=forward 2=backward
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_MOVE, wayInMm, direction, 0,0);
}


void hwapi::prn_setFonts(uint8_t font, uint8_t size, uint8_t width, uint8_t height) const
{
    // font = kind of font 0...8
    // size = 6...20, 9..9: too tiny 10: small ...12 = normal size ...20=huge
    // width:  0...4   0=1x  1=2x   2=4x (huge!)  3=8x 4=16x (3,4 make no sense)
    // heigth: 0...7 = 1x...8x  only 0,1,2,(3) make sense
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_SETFONT, font, size, width, height);
}


void hwapi::prn_setLetters(uint8_t bold, uint8_t invers, uint8_t underlined) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_SETLETT, bold, invers, underlined, 0);
}

void hwapi::prn_cut(uint8_t kindof) const
{
    // kindof = 1: full cut  2: partial cut   3=eject (5xLF + full cut)
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_CUT, kindof,0,0,0);
}

void hwapi::prn_newLine(uint8_t nrOfLines) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_LF, nrOfLines, 0, 0, 0);
}

void hwapi::prn_printCompleteFontTable(void) const
{
    sendWRcmd_setSendCommand0(SENDDIRCMD_PRN_FONTTAB);
}


void hwapi::prn_printBarcode(uint8_t kindOf, uint8_t withText,  uint8_t offset, uint8_t rotation, uint8_t dataLeng, uint8_t *data) const
{
    uint8_t buf[66], nn;
    //uint16_t uitmp;

    if (dataLeng>58)
        dataLeng=58;

    buf[0]=kindOf;
    buf[1]=withText;
    buf[2]=offset;
    buf[3]=rotation;
    buf[4]=dataLeng;
    // rest: Barcode-data:
    for (nn=0; nn<dataLeng; nn++)
        buf[5+nn]=data[nn];

    epi_store64ByteSendData( (5+dataLeng), buf);
    sendWRcmd_setSendCommand0(SENDDIRCMD_PRN_BC);
}

void hwapi::prn_sendQRdata(QByteArray *buf) const
{
    // maximal 150 alphanummeric bytes
    sub_storeSendingText(buf);
    epi_storeUserOfSendingTextBuffer(2,0,0,0,0);  // 2= print QRcode
}

void hwapi::prn_printQRcode(void) const
{
    // which was sent before
    sendWRcmd_setSendCommand0(SENDDIRCMD_PRN_QR);
}

void hwapi::prn_printLogo(uint8_t nrOfLogo, uint8_t offset ) const
{    
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_LOGO_FL, nrOfLogo, offset, 0, 0);
    pri_TD_addText("Hallo");
}


// .........................................................
// Parking Ticket (print out) designer
// .........................................................

static QByteArray ticketTemplate;

void hwapi::pri_startTicketDesign(void) const
{
    ticketTemplate.clear();

}

int hwapi::pri_TD_getCurrentSize(void) const
{
    return ticketTemplate.size();
}

bool hwapi::pri_TD_addText(QByteArray text) const
{
    if ((ticketTemplate.length() + text.length())>1278)
        return false;
    ticketTemplate.append(text);
    qDebug()<<"\nText added "<<ticketTemplate;
    return true;
}

bool hwapi::pri_TD_addValue(int val) const
{
//    QString  tmpStr;
    QByteArray  tmpStr;
    tmpStr.setNum(val,10);      // up to 12 chars
    if (ticketTemplate.length()>1266)
        return false;
    ticketTemplate.append(tmpStr);
    return true;
}

bool hwapi::pri_TD_addCommand(char group, char attribute, char p1, char p2, char p3, char p4, char p5) const
{
    // always add 8 byte to the ticket layout:  ESC & group & attribute & parameter1...5
    /* complete list of possible commands:
        group 50 : paper
            attribute 10 :  move forward
                  p1: wayInMm p2: direction
            attribute 11 : cut
                  p1: kind of, 1=full 2=partial, 3=eject
            attribute 12 : new line(s)
                  p1: nr of lines 1...100

        group 51 : fonts
            attribute 10 : kind of font     see description above
                  p1: possible: 0...22, expedient: 5...11
            attribute 11 : font size
                  p1: 6...20  12=normal   6=tiny
            attribute 12 : font width
                  p1: 0...4
            attribute 13 : font heigth
                  p1: 0...7
            attribute 14 : switch bold print on/off
                  p1: 0=off  1=on
            attribute 15 : switch invers print on/off
                  p1: 0=off  1=on
            attribute 16 : switch underlined print on/off
                  p1: 0=off  1=on

        group 52 : print graphics
            attribute 10 : print barcode with dynamic data 6 and 7
                  p1...p5 = kindOf, withText, offset, rotation, dataLeng, see description above
            attribute 11 : print QRcode with preset data

            attribute 12 : print Logo
                 p1=nrOfLogo, p2=offset

        group 53 : print dynamics
            attribute 10 : 1...8 = print dynData 0..7 at this place

*/


    char  tmpStr[10];

    // command has always fixed length of 8 byte
    if (ticketTemplate.length()>1270)
        return false;
    if (group<50 || group>59)
        return false;
    if (attribute<10 || attribute>30)
        return false;

    tmpStr[0]=0x1B;     // ESC
    tmpStr[1]=group;
    tmpStr[2]=attribute;
    tmpStr[3]=p1;
    tmpStr[4]=p2;
    tmpStr[5]=p3;
    tmpStr[6]=p4;
    tmpStr[7]=p5;

    ticketTemplate.append(tmpStr, 8);


    qDebug()<<"\ncmd added "<<ticketTemplate;
    return true;
}

bool hwapi::pri_TD_addNewLine(void) const
{

    if (ticketTemplate.length()>1277)
        return false;
    ticketTemplate.append("\n");
    return true;
}

bool hwapi::pri_TD_addSign(char sign) const
{
    if (ticketTemplate.length()>1277)
        return false;
    ticketTemplate.append(sign);
    return true;
}


char hwapi::prn_clearDocument(uint8_t documentNumber) const
{
    if (documentNumber>15)
        return false;
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_CLEARDOC, documentNumber, 0, 0, 0);
    return true;
}


bool hwapi::prn_store_Document(uint8_t documentNumber ) const
{
    // send to DC
    // documentNumber=0...15, stored in Eeprom
    // maximal 1280 bytes each
    // allowed: 0x20...0xFF, 0x0A, 0x0C, 0x1B (LF, CR, Esc)
    // 0x1B=start of embedded command (next 7bytes = command)

    if (documentNumber>15)
        return false;
    sub_storeSendingText(&ticketTemplate);
    epi_storeUserOfSendingTextBuffer(3,documentNumber,0,0,0);  // 3=store document
    return true;
}


bool hwapi::prn_printDocument(uint8_t documentNumber, struct T_dynDat *dynTicketData) const
{
    if (documentNumber>15)
        return false;
    epi_store64ByteSendData(64, &(dynTicketData->licensePlate[0]));
    sendWRcmd_setSendCommand4(SENDDIRCMD_PRN_DOC, documentNumber, 0, 0, 0);
    return true;
}






// ----------------------------------------------------------------------------------------------------------
// ------------------------------------------- MDB Bus ------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------



void hwapi::mdb_sendBusReset(void) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_RES, 0,0,0,0);

}

#define mdb_device_coinChk  0
#define mdb_device_changer  1
#define mdb_device_bill     2
//#define mdb_device_credit   3   // obsolete


void hwapi::mdb_sendCommand(uint8_t toMdbDevice, uint8_t mdbCommand) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_SENDCMD, toMdbDevice, mdbCommand, 0,0);

}

void hwapi::mdb_sendMessage(uint8_t toMdbDevice, uint8_t mdbCommand, uint8_t nrOfData, uint8_t *dataBuffer) const
{
    // nrOfData = sizeOf(dataBuffer) maximal 34 byte according mdb specs
    uint8_t myBuf[64], ii;

    tslib_strclr(myBuf, 0, 64);
    myBuf[0]=toMdbDevice;
    myBuf[1]=mdbCommand;
    if (nrOfData>34) nrOfData=34;
    myBuf[2]=nrOfData;
    for (ii=0; ii<nrOfData; ii++)
        myBuf[ii+3]=dataBuffer[ii];
    epi_store64ByteSendData(37, myBuf);
    sendWRcmd_setSendCommand0(SENDDIRCMD_MDB_SNDMSG);
}



bool hwapi::mdb_busIsReadyToWork() const
{
    return epi_restoreMdbBusReady();
}

bool hwapi::mdb_deviceVoltageOK() const
{
    return epi_restoreMdbV12Ready();
}

bool hwapi::mdb_busVoltageOk() const
{
    return epi_restoreMdbV5Ready();
}

uint8_t hwapi::mdb_getLastDeviceResponse(uint8_t *fromDevice, uint8_t *lastRequest,
                                         uint8_t *responseLength, uint8_t *responseBuffer) const
{
    // fromDevice: device nr from which data was requested 0,1,2,3
    // lastRequest: sent mdb command
    // responseLength: nr of payload data (after mdb-ack) 0...34
    // responseBuffer holds payload data (answer from mdb device)
    // return val: mdb result of this request: 1=got ACK  2=got 3xNAK  3=no or bad response    4:got Data (after ACK)


    uint8_t leng, ResData[64];

    epi_restoreMdbResponse(&leng, ResData);
    // last received mdb answer (from mdb device)
    // only needed if a special command was sent directly
    // DB0: mdb Device-Nr
    // DB1: last sent mdb command
    // DB2: lastResult   1=got ACK  2=got 3xNAK  3=no or bad response    4:got Data (after ACK)
    // DB3: nr of received (payload) data bytes (apart from ACK, can be 0....34)
    // DB4...DB39: rec.data (payload)
    *fromDevice=ResData[0];
    *lastRequest=ResData[1];
    *responseLength=ResData[3];
    tslib_strcpy(&ResData[4], responseBuffer, ResData[3]);
    return ResData[2];
}



// ----------------------------------------------------------------------------------------------------------
// --------------------------------------------- Coin Checker -----------------------------------
// ----------------------------------------------------------------------------------------------------------

void hwapi::emp_sendSettings(uint16_t coinAcceptance, uint8_t tokenChannel, uint16_t *coinDenomination ) const
{
    // coinAcceptance: bit0=coin1 (lowest donomination)  bit15=coin16  bitH=accept  bit L = deny coin (no validation)
    // tokenChannel 0...31: if this signal comes from emp then a token was inserted
    // coinDenomination = array of 16 coin values (e.g. 5, 10, 20...)

    uint8_t myBuf[64], ii, pp;
    uint16_t uitmp=coinAcceptance;

    tslib_strclr(myBuf, 0, 64);
    myBuf[0]=uint8_t (uitmp);
    uitmp>>=8;
    myBuf[1]=uint8_t (uitmp);
    myBuf[2]=tokenChannel;
    pp=3;
    for (ii=0; ii<16; ii++)
    {
        uitmp=coinDenomination[ii];
        myBuf[pp]=uint8_t(uitmp);
        uitmp>>=8;
        myBuf[pp+1]=uint8_t(uitmp);
        pp+=2;
    }

    epi_store64ByteSendData(35, myBuf);
    sendWRcmd_setSendCommand0(SENDDIRCMD_EMP_SETT);

}

void hwapi::emp_pollingOnOff(uint8_t on) const
{
    // on: 1=start polling the coin accepter  0=stop
    sendWRcmd_setSendCommand4(SENDDIRCMD_EMP_POLL, on,0,0,0);

}

void hwapi::emp_startCoinAcceptance(void) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_EMP_STARPPAY, 0,0,0,0);

}

void hwapi::emp_stopCoinAcceptance(void) const
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_EMP_STOPPAY, 0,0,0,0);

}



void hwapi::emp_getAllParameters(struct T_emp *emp) const
{
    uint8_t leng, data[66], ii, pp;
    epi_restoreEmpSettings(&leng, data);    // expected length = 64 byte

    // get 64 bytes about EMP: see h-file

    emp->gotSetup   = data[0];
    emp->state      = data[1];
    emp->shaft      = data[2];
    emp->countryCode= uchar2uint(data[4], data[3]);
    emp->scale      = data[5];
    emp->decimals   = data[6];
    for (ii=0; ii<16; ii++)
        emp->coinValues[ii] = data[7+ii];
    emp->coinAccept = uchar2uint(data[24], data[23]);
    emp->tokenChannel = data[25];
    emp->pollingRunning = data[26];
    emp->paymentRunning = data[27];

    pp=28;
    for (ii=0; ii<16; ii++)
    {
        emp->denomination[ii] = uchar2uint(data[pp+1], data[pp]);
        pp+=2;
    }
    emp->routing= uchar2uint(data[61], data[60]);

}

/*
static bool    emp_newCoin;
static uint8_t emp_newCoinSignal;
static uint16_t emp_newCoinValue;
static uint8_t emp_newCoinError;

uint8_t hwapi::emp_chkIfCoinInserted(void)
{
    // retval: 1=got coin 0xFF=emp reported an error  0=got nothing
    //          comes only one time after each coin, vaslues are stored
    uint8_t leng, data[8];

    epi_restoreEmpCoinSignal(&leng, data);
        // 5 byte per inserted coin:
        //      data[0]:   1=got coin, data set valid
        //      data[1]:   emp-signal of last inserted coin
        //      data[2]:   emp-error or warning
        //      data[3,4]: emp-value of last inserted coin 3=low byte

    //epi_clearEmpCoinSignal();

    if (data[0]>0)
    {
        emp_newCoin=data[0];  // anything came in, coin or error or both

        if (data[0] & 0x80)
        {
            emp_newCoinError=data[4];
        }
        if (data[0] &0x0F)
        {
            emp_newCoinSignal=data[1];
            emp_newCoinValue=uchar2uint(data[3], data[2]);
        }
        return emp_newCoin;
    }
    return 0;

}

uint8_t hwapi::emp_getInsertedCoinSignal(void)
{
    uint8_t uctmp=emp_newCoinSignal;
    emp_newCoinSignal=0;    // return only once
    return uctmp;

}


uint16_t hwapi::emp_getInsertedCoinValue(void)
{
    uint16_t uitmp=emp_newCoinValue;
    emp_newCoinValue=0;    // return only once
    return uitmp;
}

uint8_t hwapi::emp_getCoinError(void)
{
    uint8_t uctmp=emp_newCoinError;
    emp_newCoinError=0;    // return only once
    return uctmp;
}
*/

uint8_t hwapi::emp_chkIfCoinInserted(void) const
{
    // retval: 0...16 coins left in FIFO
    return epi_isNewCoinLeft();
}


void hwapi::emp_getNewCoinRecord(uint8_t *valid, uint8_t *signal, uint8_t *error, uint16_t *value) const
{

    epi_restoreEmpCoinSignal(valid, signal, error, value);
}

uint8_t hwapi::emp_giveLastCoin(uint16_t *value, uint8_t *signal) const
{
    // retval: 0: NO coin stored  1: valid coin  2: got wrong coin or coin denied
    // value: if retval1: value of the coin if reval=2: error number
    // signal: channel nr reported from checker

    uint8_t valid, chan, error;
    uint16_t wert;

    epi_restoreEmpCoinSignal(&valid, &chan, &error, &wert);

    if (valid && error==0xFF )
    {
        *value=wert;
        *signal=chan;
        return 1;
    }

    if (valid && error<0xFF )
    {
        *value=error;
        *signal=chan;   // normally 0, but sometimes we get both
        return 2;
    }
    return 0;
}

uint8_t hwapi::emp_returnLastCoin(uint16_t *value, uint8_t *signal) const
{
    // use this for coin changer

    uint8_t valid, chan, error;
    uint16_t wert;

    epi_restoreEmpCoinSignal(&valid, &chan, &error, &wert);

    if (error)
    {
        *value=0;
        *signal=error;
        return 0;
    }
    *value=wert;
    *signal=chan;
    return valid;
}

// ----------------------------------------------------------------------------------------------------------
// --------------------------------------------- Bill Validator -----------------------------------
// ----------------------------------------------------------------------------------------------------------
/*
// Coin checker and changer mdb4.2 / section 5
// Level 2 Commands  (predefined device msg acc. mdb manual and auto-poll)
uint8_t hwapi::mdb_bill_startPolling(bool on)
{
    // send ether one command (from list below)
    // or a poll command in the proper polling grid (e.g. every 100ms)
    epi_storeConfig08(mdbPollBills,on);
    //sendWRcmd_setSendCommand0(SENDDIRCMD_WR_CONF_08);
    return 0;
}

// the following functions tell the DC to send a mdb command to any mdb slave
// in opposite to mdb_sendData() the exact telegrams don't have to be formed here, DC does it.
uint8_t hwapi::mdb_bill_reset()
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_BillAll, 1, 0, 0, 0);

    return 0;
}

uint8_t hwapi::mdb_bill_setup()
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_BillAll, 2, 0, 0, 0);

    return 0;
}

uint8_t hwapi::mdb_bill_security(uint16_t secLevel)
{

    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_BillAll, 3, uint8_t(secLevel), uint8_t(secLevel>>8), 0);

    return 0;
}

uint8_t hwapi::mdb_bill_pollManually(void)
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_BillAll, 4, 0, 0, 0);

    return 0;
}

uint8_t hwapi::mdb_bill_billType(uint16_t billEnable, uint16_t escrowEnable)
{

    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_BillType,
                        uint8_t(billEnable), uint8_t(billEnable>>8),
                        uint8_t(escrowEnable), uint8_t(escrowEnable>>8));

    return 0;
}

uint8_t hwapi::mdb_bill_escrow(uint8_t action)
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_BillAll, 5, action, 0, 0);

    return 0;
}

uint16_t hwapi::mdb_bill_stacker(void)
{
    sendWRcmd_setSendCommand4(SENDDIRCMD_MDB_BillAll, 6, 0, 0, 0);

    return 0;
}

uint8_t hwapi::mdb_bill_expansion(uint8_t subCmd, uint8_t send[32])
{
    uint8_t sendbuf[34], nn;

    // 1) insert subCmd into buffer
    for (nn=0; nn<32; nn++)
        sendbuf[nn+1]=send[nn];
    sendbuf[0]=subCmd;
    sendbuf[33]=0;
    epi_storeMdbSendData(34, sendbuf);
    sendWRcmd_setSendCommand0(SENDDIRCMD_MDB_BillExp);
    return 0;
}


uint8_t hwapi::mdb_bill_gotPollResponse(void)
{
    // 0: no response    1: got ACK    2: got NAK    3 got ACK with additional data
    return epi_getMdbResponse();       // request only once, then epi_getMdbRecLength()==0

}


uint8_t hwapi::mdb_bill_getDataLen(void)
{
    // return nr of byte received from any mdb device
    return epi_getMdbRecLength();
}

uint8_t hwapi::mdb_bill_getPollData(uint8_t *mdb_data, uint8_t maxBufferSize)
{
    uint8_t len, buf[64], LL;
    len=epi_getMdbRecLength();
    epi_restoreMdbRecData(buf);       // request only once, then epi_getMdbRecLength()==0
    (maxBufferSize<len)?LL=maxBufferSize:LL=len;
    for (uint8_t nn=0; nn<LL; nn++ )
        mdb_data[nn]=buf[nn];
    return 0;   // OK
}

*/


// ----------------------------------------------------------------------------------------------------------
// --------------------------------------------- MODEM ------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------
/*
uint8_t hwapi::mod_getHwState(struct Tmod_hw_state *mod_hw_state)
{
    mod_hw_state->powerRdBk=epi_restoreReadDIs(DIBYTE0, RB_VGSM);
    if (epi_cntchk_swRs1toModem())
        mod_hw_state->rsSwOk=1;
    else
        mod_hw_state->rsSwOk=0;

    mod_hw_state->rsDrvOk=epi_cntchk_enabDrv01();   // can never be false
    mod_hw_state->HwState=false;
    mod_hw_state->CommState=false;
    mod_hw_state->gotAnswer=false;

    return 0;
}


uint8_t hwapi::mod_setCondition(uint16_t chgCmd)
{
    // e.g. change to state registered, sleep, open, off....
    return uint8_t(chgCmd);
}

uint16_t hwapi::mod_getCondition(void)
{
    // e.g. now socket open

    return 0;
}

bool    hwapi::mod_sendBufferFree(void)
{
    // sending allowed (before writing) and sending finished (after writing)

    return 0;
}

void    hwapi::mod_wantReadData(uint16_t nrOfData)
{
    // start reading
    nrOfData=0;

}

uint8_t hwapi::mod_sendDataBlk(uint16_t len, uint8_t *buf)
{
    len=buf[0];
    return uint8_t(len);
}

uint16_t hwapi::mod_gotData(void)
{
    // return nr of received bytes

    return 0;
}

uint8_t hwapi::mod_loadDataBlk(uint16_t len, uint8_t *buf)
{
    len=buf[0];
    return uint8_t(len);


}

uint8_t hwapi::mod_setupSerial(struct TserialParams serialParameter)
{
    // Baudrate and so on...
    return 0;
}

uint8_t hwapi::mod_getCurrentSerialSettings(struct TserialParams *serialParameter)
{
    // Baudrate and so on...

    return 0;
}
*/










// neu, 25.8.21




QString hwapi::dc_getTxt4RsDiagWin(void) const
{
    return epi_getTxt4RsDiagWin();
}

void hwapi::dc_clrTxt4RsDiagWin(void) const
{
    epi_clrTxt4RsDiagWin();
}

QString hwapi::dc_get2ndTxt4RsDiagWin(void) const
{
    return epi_get2ndTxt4RsDiagWin();
}

void hwapi::dc_clr2ndTxt4RsDiagWin(void) const
{
    epi_clr2ndTxt4RsDiagWin();
}

QString hwapi::dc_getTxt4HsStateLine(void) const
{
    // Crash!
    return epi_getTxt4HsStateLine();
}

void hwapi::dc_clrTxt4HsStateLine(void) const
{
    epi_clrTxt4HsStateLine();
}


QString hwapi::dc_getTxt4masterStateLine(void) const
{
    return epi_getTxt4masterStateLine();
}

void hwapi::dc_clrTxt4masterStateLine(void) const
{
    epi_clrTxt4masterStateLine();
}

QString hwapi::dc_getTxt4resultStateLine(void) const
{
    return epi_getTxt4resultStateLine();
}

void hwapi::dc_clrTxt4resultStateLine(void) const
{
    epi_clrTxt4resultStateLine();
}

QString hwapi::dc_getdataStateLine(void) const
{
    return epi_getTxt4dataStateLine();
}

void hwapi::dc_clrTxt4dataStateLine(void) const
{
    epi_clrTxt4dataStateLine();
}


QString hwapi::dc_getdatifLine(void) const
{
    return epi_getTxt4datifLine();
}

void hwapi::dc_clrTxt4datifLine(void) const
{
    epi_clrTxt4datifLine();
}




// using DC2 Bootloader

void hwapi::bl_iniChain(void) const
{
    dcBL_iniChain();
}


bool hwapi::bl_importBinFile(QByteArray readBinFile, uint32_t fileSize, char withDispl) const
{
    return dcBL_importBinFile(readBinFile, fileSize, withDispl);
}

uint8_t hwapi::bl_activatBootloader(uint8_t *sendData) const
{
    return dcBL_activatBootloader(sendData);
}

uint8_t hwapi::bl_startChain(void) const
{
    return dcBL_startChain();
}

uint8_t hwapi::bl_readBLversion(uint8_t *sendData) const
{
    // minimum size of sendData-buffer: 5byte  retval: length

    return dcBL_readBLversion(sendData);
}

uint8_t hwapi::bl_readFWversion(uint8_t *sendData) const
{
    // minimum size of sendData-buffer: 5byte  retval: length
    return dcBL_readFWversion(sendData);

}

uint8_t hwapi::bl_prepareDC_BLcmd(uint8_t Cmd, uint8_t SendDataLength, uint8_t *sendData, uint8_t *outBuf) const
{
// make BL protocol, retval = outbuf length (5...133)
// bring data in correct form: start always with 0x02   finish with 0x03 and append checksum
// 0x02 Cmd < ...sendData ..>  CRC  CRC 0x03
// Data length = 0...64
// special conversion: if data contain 2 or 3 (STX, ETX) then write two bytes:  0x1B (=ESC) and data|0x80
// so maxlength = 5 + 2 x 64 (if all data are 2 or 3)  without 2,3: maxlength = 5 + 64

    return dcBL_prepareDC_BLcmd(Cmd, SendDataLength, sendData, outBuf);

}

uint8_t hwapi::bl_exitBL(uint8_t *sendData) const
{
    // minimum size of sendData-buffer: 5byte  retval: length
    return dcBL_exitBL(sendData);
}

void hwapi::led_switchLedIllumination(uint8_t on) const
{
    if (on)
    {

    }

}



// neu, 25.3.23

// ------------------------------------------------------------------------------------
// 27.3.2023: Use Device-Controller's Bootloader to send hex-file
// ------------------------------------------------------------------------------------

void hwapi::bl_rebootDC(void) const
{
    uint8_t len, buf[20];

    len=dcBL_restartDC(buf);
    sendWRcmd_setSendBlock160(len, buf);
}

void hwapi::bl_startBL(void) const {
    uint8_t len, buf[20];
    memset(buf, 0x00, sizeof(buf));

    len=dcBL_activatBootloader(buf);
    sendWRcmd_setSendBlock160(len, buf);
}

bool hwapi::bl_checkBL(void) const
{
    uint8_t len, buf[20];

    //len=dcBL_readBLversion(buf);
    len=dcBL_readFWversion(buf);
    sendWRcmd_setSendBlock160(len, buf);

    return (len > 0);
}

bool hwapi::bl_isUp(void) const
{
    uint8_t receivedData[160];
    uint8_t LL;

    memset(receivedData, 0x00, sizeof(receivedData));

    LL=epi_getRawRecLength();
    if (LL>0)
    {
        epi_getRawReceivedData(receivedData);
        //epi_clrRawReceivedString();

        //qDebug() << " *** got " << LL << " data bytes from BL: " <<
         //   receivedData[0] << " " << receivedData[1] << " " << receivedData[2] << " " <<
         //   receivedData[3] << " " << receivedData[4] << " " << receivedData[5] << " ";

        // response to "readFWversion"
        if (receivedData[0]==2 && receivedData[1]==146 && receivedData[2]==45 &&
            receivedData[3]==45 && receivedData[4] ==95 && receivedData[5]==176)
        {
            dcBL_iniLoading();
            return true;
        }
        // response to "start BL"
        if (receivedData[0]==2 && receivedData[1]==101 && receivedData[2]==48 &&
            receivedData[3]==223 && receivedData[4] ==131 )
        {
            dcBL_iniLoading();
            return true;
        }

    }
    return false;
}


void hwapi::bl_sendAddress(uint16_t blockNumber) const
{
    // send start address, nr of 64byte-block, start with 0
    // will be sent only for folling block-numbers:
    // 0, 1024, 2048, 3072 and 4096, so basically every 64kByte
    uint32_t dcBL_BlkCtr=(uint32_t)blockNumber;
    uint8_t  len, buf[20];

    tslib_strclr(buf, 0, 20);
    if (dcBL_BlkCtr==0 || dcBL_BlkCtr==1024 || dcBL_BlkCtr==2048 || dcBL_BlkCtr==3072 || dcBL_BlkCtr==4096)
    {
        dcBL_BlkCtr*=64;
        len=dcBL_sendFlashStartAddr2BL(dcBL_BlkCtr, buf);   // make command string
            // uint8_t dcBL_sendFlashStartAddr2BL(uint32_t startAddr, uint8_t *sendData)
            // minimum size of sendData-buffer: 13byte    retval: length (9...13)
        sendWRcmd_setSendBlock160(len, buf);        // send command to BL
    }
}

uint8_t hwapi::bl_wasSendingAddOK(void) const
{
    // return val: 0: no response by now  1:error  10: OK

    return dcBL_sendSuccess(0x21);
    // return val: 0: no response by now  1:error  10: OK
        // lastCommand=0x21 for sendAddr or 0x22 for send data

}

void hwapi::bl_openBinary(void) const
{

    dcBL_loadBinary(0);
}

void hwapi::bl_sendDataBlock(uint8_t length, uint8_t *buffer) const
{
    // send 64 byte from bin file
    uint8_t LL=length, sendBuf[80], sendLen;
    if (LL>64) LL=64;

    tslib_strclr(sendBuf,0,80);
/*  hier ist alles richtig
    qDebug() << "bl_sendDataBlock "<<LL<< " bytes: " << buffer[0] << " " << buffer[1] << " "
     << buffer[2] << " " << buffer[3] << " " << buffer[4] << " " << buffer[5] << " "
     << buffer[6] << " " << buffer[7] << " " << buffer[8] << " " << buffer[9] << " "
    << buffer[61] << " " << buffer[62] << " " << buffer[63] << " " << buffer[64] << " "
    << buffer[65] << " " << buffer[66] << " " << buffer[67] << " " << buffer[68] << " ";
*/
    sendLen=dcBL_prepareDC_BLcmd(0x22, LL, buffer, sendBuf);   // pack into protocol frame
/*
    qDebug() << "bl_sendDataBlock "<<sendLen<< " bytes: " << sendBuf[0] << " " << sendBuf[1] << " "
     << sendBuf[2] << " " << sendBuf[3] << " " << sendBuf[4] << " " << sendBuf[5] << " "
    << sendBuf[6] << " " << sendBuf[68] << " " << sendBuf[69] << " " << sendBuf[70] << " "
    << sendBuf[71] << " " << sendBuf[72] << " " << sendBuf[73] << " " << sendBuf[74] << " ";
*/
    sendWRcmd_setSendBlock160(sendLen, sendBuf);                  // send 140 bytes
    delay(100);
}

void hwapi::bl_sendLastBlock(void) const
{
    uint8_t len, buf[20];

    len=dcBL_writeLastPage(buf);
    sendWRcmd_setSendBlock160(len, buf);

}

uint8_t hwapi::bl_wasSendingDataOK(void) const
{
    // return val: 0: no response by now  1:error  10: OK

    return dcBL_sendSuccess(0x22);
    // return val: 0: no response by now  1:error  10: OK
        // lastCommand=0x21 for sendAddr or 0x22 for send data

}

void hwapi::bl_stopBL(void) const
{
    uint8_t len, buf[20];

    len=dcBL_exitBL(buf);
    sendWRcmd_setSendBlock160(len, buf);

}
/*
bool hwapi::bl_isDiagAvailable(void) const
{

    return dcBL_checkForText();
}


QString hwapi::dc_getDiagText(void) const
{
    return dcBL_readText();    // read from 0...9 (oldest first)
}
*/

/*
// geht noch nicht //////
void hwapi::bl_startSending(void) const
{

    dcBL_startLoading();
}


void hwapi::bl_sendFile(void) const
{
//qDebug()<<" HWAPI_BL_CYCL_ISrunning ";

    dcBL_sendHexfile();

}
*/


// ------------------------------------------------------------------------------------
// 6.4.2023: new functions for coin collection and printing
//            some new system functions
// ------------------------------------------------------------------------------------

// use:
// bool sendFDcmd_set(uint8_t nextWrCmd, uint8_t nextRdCmd, uint8_t blockNum, uint8_t dat1, uint8_t dat2, uint8_t dat3, uint8_t dat4);
    // write Command to memory, wait for transport

// bool longFDcmd_set(uint8_t nextWrCmd, uint8_t nextRdCmd, uint8_t blockNum, uint8_t length, uint8_t *data);
    // write Command to memory, wait for transport
    // data buffer size always 64! data[64], padded with 0

bool hwapi::rtc_setTimeDateDirect(struct Trtc_DateTime *DateTime) const
{
    // return true if successful. could fail if more the 8 commands are waiting

    uint8_t temp[66];
    bool   b_ret;
    /* in interfaces.h:
    struct Trtc_DateTime
    {
       uint8_t rtc_hour;
       uint8_t rtc_min;
       uint8_t rtc_sec;
       uint8_t rtc_dayOfMonth;
       uint8_t rtc_month;
       uint8_t rtc_year;
       uint8_t rtc_dayOfWeek;
    };
    */
    tslib_strclr(temp,0,66);
    temp[0]= DateTime->rtc_hour;
    temp[1]= DateTime->rtc_min;
    temp[2]= DateTime->rtc_sec;
    temp[3]= 20;
    temp[4]= DateTime->rtc_year;
    temp[5]= DateTime->rtc_month;
    temp[6]= DateTime->rtc_dayOfMonth;
    temp[7]= DateTime->rtc_dayOfWeek;
    b_ret=longFDcmd_set(20,0,0,8,temp);
    return b_ret;
}

bool hwapi::rtc_getExtendedTime(uint8_t *leng, uint8_t *data) const
{
    epi_restoreExtendedTime(leng, data);
    return true;

/*
     buf[0]=GlobTime.Hours;
    buf[1]=GlobTime.Min;
    buf[2]=GlobTime.Sec;
    buf[3]=GlobTime.Year;
    buf[4]=GlobTime.Month;
    buf[5]=GlobTime.Day;
    buf[6]=GlobTime.DOW;
    buf[7]=' ';                   // immer auf 32bit auffüllen sonst Speicherproblem beim Master!
    uitmp=GlobTime.MinOfDay;
    buf[8]=swl_getOneByteFromUint(uitmp, 0);
    buf[9]=swl_getOneByteFromUint(uitmp, 1);
    buf[10]=' ';
    buf[11]=' ';
    ultmp=GlobTime.SecOfDay;
    buf[12]=swl_getOneByteFromUlong(ultmp, 0);
    buf[13]=swl_getOneByteFromUlong(ultmp, 1);
    buf[14]=swl_getOneByteFromUlong(ultmp, 2);
    buf[15]=swl_getOneByteFromUlong(ultmp, 3);

    buf[16]=swl_isLeap(GlobTime.Year);
    buf[17]=swl_getNextLeapYear(GlobTime.Year);
    buf[18]=swl_getLastLeapYear(GlobTime.Year);
    buf[19]=swl_hoursOfThisWeek(GlobTime.DOW, GlobTime.Hours);

    uitmp=swl_minutesOfThisWeek(GlobTime.DOW, GlobTime.Hours, GlobTime.Min);
    buf[20]=swl_getOneByteFromUint(uitmp, 0);    // 0=low byte   1=high byte
    buf[21]=swl_getOneByteFromUint(uitmp, 1);

    uitmp=swl_hoursOfThisMonth(GlobTime.Day, GlobTime.Hours);
    buf[22]=swl_getOneByteFromUint(uitmp, 0);
    buf[23]=swl_getOneByteFromUint(uitmp, 1);

    uitmp=swl_minutesOfThisMonth(GlobTime.Day, GlobTime.Hours, GlobTime.Min);
    buf[24]=swl_getOneByteFromUint(uitmp, 0);
    buf[25]=swl_getOneByteFromUint(uitmp, 1);

    uitmp=swl_GetDaysOfYear(GlobTime.Year, GlobTime.Month, GlobTime.Day);
    buf[26]=swl_getOneByteFromUint(uitmp, 0);
    buf[27]=swl_getOneByteFromUint(uitmp, 1);

    uitmp=swl_GetHoursOfYear(GlobTime.Year, GlobTime.Month, GlobTime.Day, GlobTime.Hours);
    buf[28]=swl_getOneByteFromUint(uitmp, 0);
    buf[29]=swl_getOneByteFromUint(uitmp, 1);
    buf[30]=0;
    buf[31]=0;
    ultmp= swl_GetMinutesOfYear(GlobTime.Year, GlobTime.Month, GlobTime.Day,
                                GlobTime.Hours, GlobTime.Min);
    buf[32]=swl_getOneByteFromUlong(ultmp, 0);
    buf[33]=swl_getOneByteFromUlong(ultmp, 1);
    buf[34]=swl_getOneByteFromUlong(ultmp, 2);
    buf[35]=swl_getOneByteFromUlong(ultmp, 3);

    buf[36]=rtc_getSqwaveSettings();
    buf[37]=0;
    buf[38]=0;
    buf[39]=0;

    ultmp= 0;       // Minutes of the Millenium
    buf[40]=swl_getOneByteFromUlong(ultmp, 0);
    buf[41]=swl_getOneByteFromUlong(ultmp, 1);
    buf[42]=swl_getOneByteFromUlong(ultmp, 2);
    buf[43]=swl_getOneByteFromUlong(ultmp, 3);

    dc2prot_setReadData(44, buf);

 */

}

bool hwapi::rtc_getExtendedTime(struct T_extTime *exTime) const
{
    uint8_t len;
    uint16_t LL, nn;
    uint8_t *start;
    uint8_t  buf[66];

    epi_restoreExtendedTime(&len, buf);
        // Puffer in struct eintragen:
    LL=sizeof(struct T_extTime);
    start = &(exTime->Hours);
    nn=0;
    do
    {
        *start = buf[nn];
        start++;
    } while(++nn<LL);

    return true;


/*
struct T_extTime
{
    uint8_t     Hours;
    uint8_t     Min;
    uint8_t     Sec;
    uint8_t     Year;
    uint8_t     Month;
    uint8_t     Day;
    uint8_t     DOW;
    uint8_t     res1;
    uint16_t    MinOfDay;
    uint16_t    res2;
    uint32_t    SecOfDay;
    uint8_t     isLeapYear;
    uint8_t     nxtLeapYear;
    uint8_t     lastLeapYear;
    uint8_t     hoursOfThisWeek;
    uint16_t    minutesOfThisWeek;
    uint16_t    hoursOfThisMonth;
    uint16_t    daysOfThisYear;
    uint16_t    GetHoursOfYear;
    uint16_t    res3;
    uint32_t    GetMinutesOfYear;
    uint8_t     getWakeIntvSec;
    uint8_t     res4;
    uint16_t    res5;
    uint32_t    MinutesOfMillenium;
};
*/

}

bool hwapi::sys_runCompleteTest(void) const
{
    // warning: lasts 20s in one pace
    return sendFDcmd_set(149, 0,0, 0,0,0,0);
}

bool hwapi::sys_ready4sending(void) const
{
    // return true if a Json-file can be sent

    // check free memory
    uint8_t frei=check4freeFDlongCmd();
        // Command-Stack sollte 16 Commands fassen, je 64byte Nutzdaten = 1024byte
        // frei gibt also die Anzahl freier 64byte Bloecke zurueck
        // das Json-File hat max 800 byte = 13 bloecke
    if (frei<16)        // Puffer muss ganz leer sein! nicht dass was durcheinander kommt
        return false;
    return true;
}

bool hwapi::sys_sendJsonFileToDc(uint8_t kindOfFile, uint8_t nrOfTemplate, uint8_t *content ) const
{
    // kindOfFile: 1=config, 2=device, 3=cash, 4=serial, 5=time, 6=printer
    //      nrOfTemplate=1...32 if kindOfFile==6
    //      content = content of the Json file, max 800byte ascii signs
    // file is 0-terminated
    // return false if sending is not possible, wait a second

    uint8_t dateiArt, NummDesTempl;
    uint8_t inhaltOfJson[802], temp[66];
    uint16_t dateiLang, uitmp;
    uint8_t nrOfBlocks;
    uint8_t frei, bn=0;

    dateiArt=kindOfFile;
    NummDesTempl=nrOfTemplate;
    tslib_strclr(inhaltOfJson,0,801);
    dateiLang=tslib_strlen(content);
    if (dateiLang>800) dateiLang=800;
    tslib_strcpy(content, inhaltOfJson, dateiLang); // enthaelt genaue Laenge, Rest =0
    nrOfBlocks=dateiLang/64;
    if (dateiLang%64>0)
        nrOfBlocks++;
    dateiLang=nrOfBlocks;
    dateiLang<<=6;  // auf volle 64byte aufgerundet

    // check free memory
    frei=check4freeFDlongCmd();
        // Command-Stack sollte 16 Commands fassen, je 64byte Nutzdaten = 1024byte
        // frei gibt also die Anzahl freier 64byte Bloecke zurueck
        // das Json-File hat max 800 byte = 13 bloecke
    if (frei<16)        // Puffer muss ganz leer sein! nicht dass was durcheinander kommt
        return false;

    // Start- und Stop auch als langes Kommando schicken
    // PROBLEM: wuerden sie in einem anderen Batch gespeichert (short command stack),
    //          dann kann die Reihenfolge nicht gewaehrleistet werden
    //          Das Startkommando muss sicher zuerst kommen
    //          Das Abschlusskommando muss sicher zuletzt kommen

    tslib_strclr(temp,0,65);
    temp[0]=dateiArt;
    temp[1]=NummDesTempl;
    longFDcmd_set(30, 0,0, 2,temp);      // sende "Starte-file-DL"
    uitmp=0; bn=0;
    do
    {
        biox_CopyBlock(inhaltOfJson, uitmp, temp, 0, 64);
        longFDcmd_set(31,0, bn++, 64, temp);
        //uitmp<<=6;  // falsch
        uitmp+=64;
    } while(uitmp < dateiLang);

    longFDcmd_set(32, 0,0, 0,temp);       // Abschluss

    return true;
}

//char prn_dynPrnVal[8][8];
bool hwapi::prn_sendDynamicPrnValues(uint8_t *dynPrnVal ) const
// dynPrnVal = array of 8 Variables with 8 byte each, come as ascii string
//            like:     char prn_dynPrnVal[8][8];
// return true if sending, false if cmd-stack is full
{

    uint8_t  temp[66];


    tslib_strcpy(dynPrnVal, temp, 64); // Vorsicht, kann \0en enthalten
    return longFDcmd_set(33,0,0, 64, temp);

}


bool hwapi::prn_printTemplate(uint8_t nrOftemplate) const
    // print one of the templates loaded by Json prior
    // nr = 1..32
{
    // return true if sending, false if cmd-stack is full

    // 3.5.23: die dynVals und alle templates sollen am stück gesendet
    uint8_t data[64];
    data[0]=nrOftemplate;
    return longFDcmd_set(152, 0,0, 1, data);
}

void hwapi::log_getHoldAccountNumbers(uint8_t *nrOfVals, uint16_t *accNr ) const
{
    // returns all acc nrs of the backuped vault records
    // use: uint16_t backupedAccNumbers[8]

    epi_restoreDCbackupAccNr(nrOfVals, accNr);
}



bool hwapi::log_selectVaultRecord(uint16_t accountNr ) const
{
    // return true if sending, false if cmd-stack is full
    // and trigger transfer

    uint8_t dat1, dat2;
    bool ret;

    uint8_t frei=check4freeFDshortCmd();
    if (frei<8)
        return false;

    epi_iniVRstorage();
    dat1=uint2uchar(accountNr, LOWBYTE);
    dat2=uint2uchar(accountNr, HIGHBYTE);
    ret=sendFDcmd_set(153, 0,0, dat1,dat2,0,0); // select this record
        // true means "will be sent"
    sendFDcmd_set(0,38,0, 0,0,0,0);    // return VaultRecord block-Nr.0
    sendFDcmd_set(0,38,1, 0,0,0,0);    // return VaultRecord block-Nr.1
    sendFDcmd_set(0,38,2, 0,0,0,0);    // return VaultRecord block-Nr.2
    sendFDcmd_set(0,38,3, 0,0,0,0);    // return VaultRecord block-Nr.3
    sendFDcmd_set(0,38,4, 0,0,0,0);    // return VaultRecord block-Nr.4
    sendFDcmd_set(0,38,5, 0,0,0,0);    // return VaultRecord block-Nr.4
        // 38: <100 to get long 64byte response

    return ret;
}

bool hwapi::log_chkIfVaultRecordAvailable(void) const
{
    // return true if completly received
    return epi_checkIfVaultRecordAvailable();
        return false;
}

bool hwapi::log_getVaultRecord(struct T_vaultRecord *retVR) const
    // which was selected by: log_selectVaultRecord()
    // to be forwarded to Ismas
    // return true if completly received
{

    uint16_t LL, nn, len;
    char   *start;
    uint8_t  buf[400];
    bool ret;

    ret=epi_restoreVaultRecord(&len, buf);   // true if completly received
    if (ret==false)
        return false;
        // Puffer in struct eintragen:
    LL=sizeof(struct T_vaultRecord);		// =320
    start = &retVR->startbuffer[0];
    nn=0;
    do
    {
        *start = buf[nn];
        start++;
    } while(++nn<LL);
    return true;
}

bool hwapi::prn_printAccountReceipt(void) const
{
    return sendFDcmd_set(154, 0,0, 0,0,0,0);
}

bool hwapi::prn_printTestTicket(void) const
{
    // return true if sending to DC OK, false if cmd-stack is full
    return sendFDcmd_set(157, 0,0, 0,0,0,0);

}

bool hwapi::cash_startPayment(uint32_t amount) const
{
    // 17.4.23TS: extended to 32bit
    uint8_t dat1, dat2, dat3, dat4;

    hwapi_lastStartAmount=amount;
    epi_clearCurrentPayment();
    dat1=ulong2uchar(amount, 0);
    dat2=ulong2uchar(amount, 1);
    dat3=ulong2uchar(amount, 2);
    dat4=ulong2uchar(amount, 3);

    return sendFDcmd_set(155, 0,0, dat1,dat2,dat3,dat4);

}

uint32_t hwapi::getInsertedAmount(void) const
{
    return epi_CurrentPaymentGetAmount();
}

uint16_t hwapi::getLastInsertedCoin(void) const
{
    return epi_CurrentPaymentGetLastCoin();
}

bool hwapi::getAllInsertedCoins(uint16_t *types, uint16_t *values) const
{
    // alle bei diesem Verkauf eingeworfenen Münzen sind gespeichert, max 64
    return epi_CurrentPaymentGetAllCoins(types, values);

}


bool hwapi::cash_cancelPayment(void) const
    // and return coins
{
    // DB1: 1=encash    2=cancel & return coins
    //      3=stop and keep coins in escrow
    return sendFDcmd_set(156, 0,0, 2,0,0,0);
}
bool hwapi::cash_stopPayment(void) const
    // and keep coins in escrow
{
    // DB1: 1=encash    2=cancel & return coins
    //      3=stop and keep coins in escrow
    emit hwapi_vendStopByPushbutton();
    return sendFDcmd_set(156, 0,0, 3,0,0,0);

}
// after ticket/goods issue:
bool hwapi::vend_success(void) const
    // conclude payment process, encash all inserted coins to vault. Printing was successful
    // if possible return change
{
    // DB1: 1=encash    2=cancel & return coins
    //      3=stop and keep coins in escrow
    return sendFDcmd_set(156, 0,0, 1,0,0,0);

}
bool hwapi::vend_failed(void) const
    // conclude payment process and return all inserted coins
{
    // DB1: 1=encash    2=cancel & return coins
    //      3=stop and keep coins in escrow
    return sendFDcmd_set(156, 0,0, 2,0,0,0);

}

uint8_t hwapi::mif_getCardType(QString *cardholder) const
    // return 1,2,3,4 = upper, lower access card, printer test, coin test
    // cardholder: 7byte Name-String
{
    uint8_t type, buf[8], nn;
    char ctmp;

    memset(buf, 0x00, sizeof(buf));

    type=epi_mifGetCardType(&buf[0]);
        //holder[8] = name of card holder
        // retval Type of MifareCard, 1=upper door, 2=lower door 3=test printer 4=test coins
    for (nn=0;nn<8; nn++) {
        ctmp=buf[nn];
        cardholder[nn]=ctmp;

    }
    return type;
}

uint64_t hwapi::sys_getWakeSource(void) const
{
    // retval: 6 bytes, bit coded, 1=event keeps DC awake
     return epi_getWakeSources();
}

uint8_t hwapi::sys_getWakeReason(void) const
{
     // Master was woken by following reason:
     // 1: MDB Event
     // 2: Coin Event
     // ( 3: Master Event) - will not set the wake line
     // ( 4: 32s pulse) - will not set the wake line
     // 5: Door Event
     // ( 6: Diag Event) - will not set the wake line
     // 7: 30min-Pulse for HB

     return epi_getWakeReason();
}


void hwapi::sys_getDeviceConditions(uint8_t *leng, uint8_t *data) const
{
    //uint8_t leng, data[66];
    epi_restoreDeviceConditions(leng, data);
}

void hwapi::sys_getDeviceConditions(struct T_moduleCondition *devCond) const
{
    uint16_t LL, nn;
    uint8_t *start;
    uint8_t  buf[70], leng;

    epi_restoreDeviceConditions(&leng, buf);

        // Puffer in struct eintragen:
    LL=sizeof(struct T_moduleCondition);
    start = &devCond->ram;
    nn=0;
    do
    {
        *start = buf[nn];
        start++;
    } while(++nn<LL);

}




void hwapi::sys_getDynMachineConditions(uint8_t *leng, uint8_t *data) const
{
    epi_restoreDynMachineConditions(leng, data);
}

void hwapi::sys_getDynMachineConditions(struct T_dynamicCondition *dynMachCond) const
{

    uint16_t LL, nn;
    char *start;
    uint8_t  buf[70], leng;

    epi_restoreDynMachineConditions(&leng, buf);
        // Puffer in struct eintragen:
    LL=sizeof(struct T_dynamicCondition);
    start = &dynMachCond->allDoorsDebounced;
    nn=0;
    do
    {
        *start = buf[nn];
        start++;
    } while(++nn<LL);

}


uint32_t hwapi::cash_getAmountInVault(void) const
{
    return epi_getCashBoxContent();
}

uint16_t hwapi::cash_getNrCoinsInVault(void) const
{
    return epi_getNrOfCoinsInCashBox();
}



uint8_t hwapi::prn_getPrintResult() const
{
    // return:  0: unknown
    //          1: OK - last template was printed succesful
    //          2: error - last template was not printed

    struct T_dynamicCondition dynMachCon;
    //uint8_t  buf[70], leng,
    uint8_t res;
    static  uint8_t lastState;
    //uint32_t  aa;

   // aa=&dynMachCon;
    sys_getDynMachineConditions(&dynMachCon);
    res= dynMachCon.resultOfLastTemplPrint;
        // 0: unknown or printing in progress
        // 1: OK, doc was printed   2: error, doc was not printed

    if (res==0)
    {
        if (lastState>0)
        {
            // print was started
            lastState=res;
        }
    } else
    {
        if (lastState==0)
        {
            // result hat sich auf 1 oder 2 geändert, d.h. Druck ist fertig
            if (res==1)
            {

                //emit    hwapi_templatePrintFinished_OK();
            } else
            if (res==2)
            {

                //emit    hwapi_templatePrintFinished_Err();
            }
                lastState=res;
        }
    }
    return res;
}

uint8_t hwapi::prn_getCurrentPrinterState() const
{
        //        0: printer OK
        //          bit0: near paper end          bit1: no paper
        //          bit2: temperature error       bit3: error head open
        //          bit4: paper jam in cutter
        //          bit6: no response             bit7: serial rec. error
        //			bit5: printer not ready


    uint8_t     lastPrinterStatus;
    uint8_t  buf[70], leng;

    // 2nd way to get dyn.conditions:
    epi_restoreDynMachineConditions(&leng, buf);
    lastPrinterStatus=buf[53];

    return lastPrinterStatus;
}


// 21.4.23TS: change function "sendDeviceSettings()" to use this struct: "struct T_devices"
void hwapi::sys_sendDeviceParameter(struct T_devices *deviceSettings) const
{
    // same as "sendDeviceSettings()" but with much more data
    uint8_t buf[64];
    uint16_t LL, nn;
    tslib_strclr(buf,0,64);
    uint8_t *start;

    // den gesamten struct in einen Puffer kopieren
    LL=sizeof(struct T_devices);
    start = &deviceSettings->kindOfPrinter;
    nn=0;
    do
    {
        buf[nn] = *start;
        start++;
    } while(++nn<LL);

    epi_store64BdevParameter(LL,buf);   // this buffer holds the device settings to be used here in hwapi
    epi_store64ByteSendData(LL, buf);   // this buffer holds sending data temporarely
    sendWRcmd_setSendCommand0(SENDDIRCMD_DEVICE_PARA);

}

void hwapi::sys_restoreDeviceParameter(struct T_devices *deviceSettings) const
{
    uint8_t buf[64];
    uint8_t LL, nn;
    tslib_strclr(buf,0,64);
    uint8_t *start;

    epi_restore64BdevParameter(&LL, buf);

    // Puffer in struct eintragen:
    start = &deviceSettings->kindOfPrinter;
    nn=0;
    do
    {
        *start = buf[nn];
        start++;
    } while(++nn<LL);

}



/* ---------------------------------------------------------------------------------------------
// ------------   supervise  all hardware components
// ------------    assess the machine state

1. check if DC startup test is through, retrigger if not
2. get results and find errors
3. in case of error check if component is used (e.g. billreader is seldom used)
4: check doors
5. return value: 0: no response from DC
                 1: no Test results and Test not running. need retrigger!
                 2: state not clear by now, test ongoing, wait
                 3: Service or battery door is open, goto INTRUSION MODE
                        from here: after valid ID-card goto SERVICE MODE
                 4: vault door is open, goto INTRUSION MODE
                        from here: after valid ID-card and vault door closed goto TEST MODE
                        in TEST MODE: complete system check decides if vending mode allowed
                 5: All doors are closed but errors found,
                        goto OOO MODE (out-of-order)
                        from here: run system test until problem is fixed
                 6: All doors are closed, no error, maybe warnings,
                        goto VENDING MODE (normal operation)
                (priority sinks from 0 to 6)

 --------------------------------------------------------------------------------------------- */

uint8_t hwapi::sys_componentAssessment(void) const
{
    // this function decides if vending mode is possible, independant from door
    // return >0 in case of error
    // is inncluded in sys_superviseSystem

    struct T_moduleCondition *modCond=0;
    sys_getDeviceConditions(modCond);

    struct T_dynamicCondition *dynMaCond=0;
    sys_getDynMachineConditions(dynMaCond);

    struct T_devices *devPara=0;
    sys_restoreDeviceParameter(devPara);

    if (modCond->rtc>=200)
        return 1;
    if (modCond->printer==200 || modCond->printer==201)   // 200: not connected  201: printer-HW-error  202: no paper
        return 2;
    if (modCond->printer==202)
        return 3;

    if (modCond->coinBlocker>=200)
        return 4;
    if (modCond->mdbBus>=200)
        return 5;
    if (modCond->intEe>=200)
        return 6;

    if (devPara->kindOfCoinChecker==1 || devPara->kindOfCoinChecker==2)  // 0: without  1=EMP820   2=EMP900    3=currenza c²	(MW)
    {
        if (modCond->coinChecker>=200 || modCond->coinEscrow>=200)
        {
            // Fehler Münzver.
            return 7;
        }
        if (modCond->coinSafe>200)           // 200: kasse fehlt 201: voll  100:fast voll  1:ok
        {
            return 8;
        }
    } else
    if (devPara->kindOfCoinChecker==3)
    {
        if (modCond->changer>=200)
        {
            // Fehler Münzver.
            return 7;
        }
        if (modCond->coinSafe>200)           // 200: kasse fehlt 201: voll  100:fast voll  1:ok
        {
            return 8;
        }
    }

    if ( modCond->billReader>=200 && devPara->BillAcceptor>0)
    {
        // Fehler BNA
        return 9;
    }

    if (dynMaCond->onAlarm>0)
        return 10;

    if (dynMaCond->modeAbrech>0)
        return 11;

    if (dynMaCond->nowCardTest>0)
        return 12;

    if (dynMaCond->startupTestIsRunning>0)
        return 13;

    if (modCond->voltage>=200)
        return 14;
    if (modCond->temper>=200)
        return 15;

    return 0;
}


// retrigger System-Check with:
// bool hwapi::sys_runCompleteTest(void) const


uint8_t hwapi::sys_superviseSystem(void) const
{
    // this function proofs if vending is possible depending of doors state

    struct T_dynamicCondition *dynMaCond=0;
    struct T_moduleCondition *modCond=0;

    if (!gpi_areDcDataValid())
    {
        // es gibt keinerlei gültige Daten vom DC
        return 0;
    }

    // jetzt sind die DC-Daten aktuell, also reinholen:
    sys_getDynMachineConditions(dynMaCond);
    sys_getDeviceConditions(modCond);

    if (!modCond->allModulesChecked)
    {
        // noch keine Testergebnisse
        if (dynMaCond->startupTestIsRunning)
            return 2;    // Starttest läuft gerade
        else
            return 1;    // Starttest ist noch nicht gelaufen
    }

    // all doors: 99: undefined  0:closed  1:open
    if (dynMaCond->lowerDoor || dynMaCond->upperDoor)
        return 3;
    if (dynMaCond->middleDoor)
        return 4;

    if (sys_componentAssessment() >0)
        return 5;       // errors found

    return 6;   // everything fine
}



uint8_t hwapi::sys_getSystemErrors(void) const
{

    return sys_componentAssessment();


}


