/*
 * 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;
    for (int i = 0; i < templateIdx.size(); ++i) {
        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();
}








// ------------------------------------------------------------------------------
// Level4   devices are operated by DC
//          processes with more then one devices
//          timer controlled or long term processes
// ------------------------------------------------------------------------------




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
    return sendFDcmd_set(152, 0,0, nrOftemplate,0,0,0);
}

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();
}


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;
}