//#include <stdint.h>
#include "dcBL.h"
#include <QDebug>
//#include "tabFw.h"
#include "sendWRcmd.h"


// File sits "behind" the HWapi and in front of "PI", so all necessary Bootloader functions can be called from HWapi



uint16_t ucharTOuint(uint8_t Highbyte, uint8_t Lowbyte)
{
    uint16_t uitmp;
    uitmp=0;
    uitmp |= uint8_t(Highbyte);
    uitmp<<=8;
    uitmp |= uint8_t(Lowbyte);
    return uitmp;
}

#define GETLOWBYTE      0
#define GETHIGHBYTE     1

uint8_t uintTOuchar(uint16_t uival, uint8_t getHighB)
{
    // getHighB: low=GetLowByte
    uint16_t uitmp=uival;
    if (getHighB==0)
        return uint8_t(uitmp);
    uitmp>>=8;
    return uint8_t(uitmp);

}

//#define GETLOWBYTE      0
//#define GETHIGHBYTE     1
#define GETMIDLOWBYTE      2
#define GETMIDHIGHBYTE     3

uint8_t ulongTOuchar(uint32_t ulval, uint8_t whichByte)
{

    uint32_t ultmp=ulval;
    if (whichByte==GETLOWBYTE)
        return uint8_t(ultmp);
    ultmp>>=8;
    if (whichByte==GETMIDLOWBYTE)
        return uint8_t(ultmp);
    ultmp>>=8;
    if (whichByte==GETMIDHIGHBYTE)
        return uint8_t(ultmp);
    ultmp>>=8;
    if (whichByte==GETHIGHBYTE)
        return uint8_t(ultmp);
    return 0;
}

void strclr(uint8_t *buf, uint8_t clrsign, uint8_t len)
{
    uint16_t nn;

    for (nn=0; nn<len; nn++)
        buf[nn]=clrsign;

}

// -----------------------------------------------------------------------------------------------
// communication with this particular DeviceController's Bootloader ---------------------------------
// -----------------------------------------------------------------------------------------------

uint16_t dcBL_calcCrcCcitt(uint32_t BufLength, uint8_t *buf)
{
    // CRC16 / CCITT-FALSE
    uint8_t  nn, B15H, element;
    uint16_t crc = 0x84cf;


    while (BufLength--)
    {
        element = *buf++;
        for (nn = 0; nn < 8; nn++)
        {
            B15H = 0;
            if(crc & 0x8000)
                B15H = 1;
            crc = (crc << 1) | ((element >> (7 - nn)) & 0x01);
            if (B15H)
            {
                crc ^= 0x1021;
            }
        }
    }

    for (nn = 0; nn < 16; nn++)
    {
        B15H = 0;
        if(crc & 0x8000)
        B15H = 1;
        crc = (crc << 1) | 0x00;
        if (B15H)
        {
            crc ^= 0x1021;
        }
    }
    return crc;

}


#define     SEND_STX    2
#define     SEND_ETX    3
#define     SEND_ESC    0x1B

static uint8_t dcBL_LastBLcmd;   // stored the last sent cmd in order to analys response
                            // cmd echo'ed: error       cmd or'ed with 0x80: OK

uint8_t dcBL_prepareDC_BLcmd(uint8_t Cmd, uint8_t SendDataLength, uint8_t *sendData, uint8_t *outBuf)
{
    // 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

    // 26.01.2021: noch einen Fehler gefunden: die "special conversion" fehlt bei der angehaengten Checksumme!!!

    uint8_t  myBuf[140], pp=0, HB, LB;
    uint8_t  crcBuf[140], mm=0;
    uint8_t  nn, uctmp, currLen=0;
    uint16_t calcCrc;

    strclr(myBuf, 0, 140);
    strclr(crcBuf, 0, 140); // extra Puffer because STX must not be caculated

    myBuf[pp++]=SEND_STX;
    myBuf[pp++]=Cmd;
    crcBuf[mm++]=Cmd;
    dcBL_LastBLcmd=Cmd;

    // append data:
    for (nn=0; nn<SendDataLength; nn++)
    {
        uctmp=sendData[nn];
        if (uctmp==SEND_STX || uctmp==SEND_ETX || uctmp==SEND_ESC)       // ESC, STX or ETX in payload
        {
            myBuf[pp++]=SEND_ESC;
            //crcBuf[mm++]=SEND_ESC;        // so wäre die Berechnung NACH der Umwandlung, ist aber falsch
            myBuf[pp++]=uctmp | 0x80;
            //crcBuf[mm++]=uctmp | 0x80;    // so wäre die Berechnung NACH der Umwandlung, ist aber falsch
            crcBuf[mm++]=uctmp;         // crc VOR umwandlung berechnen!
        } else
        {
            myBuf[pp++]=uctmp;
            crcBuf[mm++]=uctmp;
        }
    }
    currLen=mm;

    // calc crc: (over cmd and data, without STX)
    //qDebug() << "calc crc: anzahl  " <<mm;
    //qDebug() << crcBuf;
    calcCrc=dcBL_calcCrcCcitt(uint32_t(currLen), crcBuf);
    //qDebug() << calcCrc;

//    myBuf[pp++]=uintTOuchar(calcCrc, GETHIGHBYTE);
//    myBuf[pp++]=uintTOuchar(calcCrc, GETLOWBYTE);
//    myBuf[pp++]=SEND_ETX;

    // 26.01.2021: die "special conversion" auch für die angehaengte Checksumme:
    HB=uintTOuchar(calcCrc, GETHIGHBYTE);
    LB=uintTOuchar(calcCrc, GETLOWBYTE);
    uctmp=HB;
    if (uctmp==SEND_STX || uctmp==SEND_ETX || uctmp==SEND_ESC)       // ESC, STX or ETX in payload
    {
        myBuf[pp++]=SEND_ESC;
        myBuf[pp++]=uctmp | 0x80;
        crcBuf[mm++]=uctmp;
    } else
    {
        myBuf[pp++]=uctmp;
        crcBuf[mm++]=uctmp;
    }
    uctmp=LB;
    if (uctmp==SEND_STX || uctmp==SEND_ETX || uctmp==SEND_ESC)       // ESC, STX or ETX in payload
    {
        myBuf[pp++]=SEND_ESC;
        myBuf[pp++]=uctmp | 0x80;
        crcBuf[mm++]=uctmp;
    } else
    {
        myBuf[pp++]=uctmp;
        crcBuf[mm++]=uctmp;
    }
    myBuf[pp++]=SEND_ETX;

    currLen=pp;

    for (nn=0; nn<currLen; nn++)
        outBuf[nn]=myBuf[nn];

    if (outBuf[currLen-1] !=3)
    {
        qDebug()<<"protocol error no ETX, len="<< currLen << " data: " << myBuf;
    }
    return currLen;
}

// some special commands (right out of bootloader manual)
uint8_t dcBL_readBLversion(uint8_t *sendData)
{
    // minimum size of sendData-buffer: 5byte  retval: length
    uint8_t myBuf[2];
    strclr(myBuf, 0, 2);
    return dcBL_prepareDC_BLcmd(0x11, 0, myBuf, sendData);
}

uint8_t dcBL_readFWversion(uint8_t *sendData)
{
    // minimum size of sendData-buffer: 5byte  retval: length
    uint8_t myBuf[2];
    strclr(myBuf, 0, 2);
    return dcBL_prepareDC_BLcmd(0x12, 0, myBuf, sendData);
}

uint8_t dcBL_exitBL(uint8_t *sendData)
{
    // minimum size of sendData-buffer: 5byte  retval: length
    uint8_t myBuf[2];
    strclr(myBuf, 0, 2);
    return dcBL_prepareDC_BLcmd(0x18, 0, myBuf, sendData);
}

uint8_t dcBL_sendFlashStartAddr2BL(uint32_t startAddr, uint8_t *sendData)
{
    // minimum size of sendData-buffer: 13byte    retval: length (9...13)
    uint8_t myBuf[5];

    myBuf[0]=ulongTOuchar(startAddr, GETHIGHBYTE);
    myBuf[1]=ulongTOuchar(startAddr, GETMIDHIGHBYTE);
    myBuf[2]=ulongTOuchar(startAddr, GETMIDLOWBYTE);
    myBuf[3]=ulongTOuchar(startAddr, GETLOWBYTE);
    myBuf[4]=0;

    return dcBL_prepareDC_BLcmd(0x21, 4, myBuf, sendData);
}

uint8_t dcBL_writeLastPage(uint8_t *sendData)
{
    // return the necessary command to tell the BL "finish writing" =write last page even if not full
    // minimum size of sendData-buffer: 5byte  retval: length
    uint8_t myBuf[2];
    strclr(myBuf, 0, 2);
    return dcBL_prepareDC_BLcmd(0x22, 0, myBuf, sendData);
}

uint8_t dcBL_restartDC(uint8_t *sendData)
{
    // minimum size of sendData-buffer: 20 byte  retval: length

    // send this data block in decimal:  2 81 67 34 85 91 45 52 66 77 88 210 211 3
    uint8_t nn=0;
    sendData[nn++]=2;
    sendData[nn++]=81;
    sendData[nn++]=67;
    sendData[nn++]=34;
    sendData[nn++]=85;
    sendData[nn++]=91;
    sendData[nn++]=45;
    sendData[nn++]=52;
    sendData[nn++]=66;
    sendData[nn++]=77;
    sendData[nn++]=88;
    sendData[nn++]=210;
    sendData[nn++]=211;
    sendData[nn++]=3;
    sendData[nn++]=0;
    sendData[nn++]=0;
    return nn;
}

uint8_t dcBL_activatBootloader(uint8_t *sendData)
{
    // minimum size of sendData-buffer: 20 byte  retval: length
    uint8_t nn=0;

    //sendData[nn++]='U';  nötig??
    sendData[nn++]='U';
    sendData[nn++]='U';
    sendData[nn++]='U';
    sendData[nn++]='U';
    sendData[nn++]='U';

    sendData[nn++]=2;
    sendData[nn++]='c';
    sendData[nn++]='4';
    sendData[nn++]='5';
    sendData[nn++]='b';
    sendData[nn++]='3';
    sendData[nn++]=3;

    sendData[nn++]='U';
    sendData[nn++]='U';
    sendData[nn++]='U';
    sendData[nn++]='U';
    sendData[nn++]='U';
    sendData[nn++]=0;
    return nn;
}

// -----------------------------------------------------------------------------------------------

uint8_t dcBL_getResponse(uint8_t *respBuff, bool display)
{
    // retval: nr of received bytes
    uint8_t recLen=epi_getRawRecLength();
    if (recLen>0 && recLen<150)
    {
        epi_getRawReceivedData(respBuff);
        epi_clrRawReceivedString();
        dcBL_writeText("dcBL gotResponse");

        if (display)
        {
/*
            // Antwort ins Fenster schreiben:
            QString tmpStr="", myStr="~~> ";

            tmpStr.setNum(recLen);
            myStr.append(tmpStr);
            myStr.append(" bytes received: ");
            for (int nn=0; nn<recLen; nn++)
            {
                tmpStr.clear();
                tmpStr.setNum(respBuff[nn]);
                myStr.append(tmpStr);
                myStr.append(" ");
            }
            dcBL_writeText(myStr);
*/
        }
    }
    return recLen;
}

#define noReceive       0
#define ISWRONG         1
#define ISOK            10

uint8_t dcBL_ChkResponse()
{
    // retval: 0: no response (by now)
    // 1...5: Error, repeat
    // 10: OK, next...
    uint8_t buf[152], recLen;
    //uint8_t exactError;
    //QString tmpStr="";

    //exactError=0;
    recLen=dcBL_getResponse(buf,0);
    if (recLen==0)
        return 0;    // no response by now

//qDebug()<<" DCBL_chkResp got answer " << recLen   ;
//dcBL_writeText("DCBL_chkResp got answer");

    if (buf[0]==2 && buf[1]==(dcBL_LastBLcmd | 0x80) )
        return 10;    //  OK

    // 27.01.21: Problem aufgetaucht: Fehler nur bei CRC melden
    // -> block wiederholen. In den anderen Fällen NICHT wiederholen
    // sonst ist der block doppelt im Flash!!!!!!!!
    if (recLen>0 && recLen<5)
    {
        dcBL_writeText("error wrong length");
        //exactError=1;
qDebug()<<" DCBL_chkResp wrong length ";
        return 10;    //  OK
    }
    if (buf[0] !=2)
    {
        dcBL_writeText("error wrong start");
        //exactError=2;
qDebug()<<" DCBL_chkResp wrong start ";
        return 10;    //  OK
    }
    if (buf[0]==2 && buf[1]=='e' && buf[2]=='0' )
    {
        dcBL_writeText("error wrong crc");
        //exactError=3;   // DC reports wrong crc
qDebug()<<" DCBL_chkResp wrong crc";
        return 1;   // error
    }
    if (buf[0]==2 && buf[1]==dcBL_LastBLcmd )
    {
        dcBL_writeText("error wrong cmd");
        //exactError=4;    // wrong cmd
qDebug()<<" DCBL_chkResp wrong cmd";
        return 10;    //  OK
    }
    //tmpStr.clear();
    //tmpStr.setNum(exactError);
    //dcBL_writeText(tmpStr);
    return 1;   // error
}



uint8_t dcBL_sendSuccess(uint8_t lastCommand)
{
    // return val: 0: no response by now  1:error  10: OK

    uint8_t buf[152], recLen;

    recLen=dcBL_getResponse(buf,0);
    if (recLen==0)
        return 0;    // no response by now

    if (buf[0]==2 && buf[1]==(lastCommand | 0x80) )
        return 10;    //  OK
    return 1;
}

// -----------------------------------------------------------------------------------------------
// --- ATB Bin-File Handling ---------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------

/* example read file from HDD:
    uint8_t uit8tmp;
    QString stemp=" ";

    QFile file("/own/H2B/dc2.bin");
    //QFile file("/own/H2B/dc2.hex");   // laesst sich genauso oeffnen

    // TODO: use File-Open-Dialog-Box

    if (!file.exists())
    {
        qDebug()<<"file not exists";
    } else
    {
        if (!file.open(QIODevice::ReadOnly)  )
        {
            qDebug()<<"cannot open";
        } else
        {
            qDebug()<<"loading....";
            qDebug()<<"size: " << file.size() <<"\n";
            QByteArray myBin = file.readAll();

            // Kontrolle:
            int ii=0;
            do
            {
                uit8tmp=(uint8_t)myBin[ii++];
                //qDebug() << uit8tmp << " "; // Anzeige in dez
                stemp.setNum(uit8tmp,16);
                qDebug() << stemp << " ";   // Anzeige in hex

            } while (ii<100);
        }
    }

  */


// -------------------------------------------------------------------------

char dcBL_loadBinary(char withDisplay)
{
    // same function as in "tabFw"
    //uint8_t uit8tmp;
    uint32_t ultmp, fileLen;
    QString tmpStr="", s2tmp="";

    qDebug()<<"dcBL loading DC2c binary...";
    QFile file("../dc2c4.bin");
    if (!file.exists())
    {
        //qDebug()<<"file _own_H2B_dc2.bin does not exist";
        dcBL_writeText("file _own_H2B_dc2.bin does not exist");
        return 1;
    }
    if (!file.open(QIODevice::ReadOnly)  )
    {
        //qDebug()<<"cannot open";
        dcBL_writeText("cannot open");
        return 1;
    }

    //qDebug()<<"loading....";
    //qDebug()<<"size: " << file.size() <<"\n";
    if (withDisplay)
    {
        s2tmp="loading file with ";
        tmpStr.setNum(file.size());
        s2tmp.append(tmpStr);
        s2tmp.append(" bytes");
        dcBL_writeText(s2tmp);
    }
    QByteArray myBin = file.readAll();
    fileLen=uint32_t(file.size());

    // Rest des Blockes mit 0xFF füllen
    for (ultmp=fileLen; ultmp<(fileLen+70); ultmp++)
        myBin[ultmp]=char(0xFF);

    /* // Kontrolle:
    qDebug()<<"dcBL_loadBinary: ";
    int ii=59500;
    do
    {
        uit8tmp=uint8_t(myBin[ii++]);
        s2tmp.clear();
        //qDebug() << uit8tmp << " "; // Anzeige in dez
        s2tmp.setNum(uit8tmp,16);
        qDebug() << s2tmp << " ";   // Anzeige in hex

    } while (ii<60100);
    */

    dcBL_importBinFile(myBin, fileLen, withDisplay);
    return 0;

}


static QByteArray   dcBL_AtbBinFile;
static uint32_t     dcBL_fileSize;
static uint16_t     dcBL_nrOfBlocks;
static uint16_t     dcBL_fileCrc;
//static uint8_t      dcBL_myBuf[2570000]; // same content like "dcBL_AtbBinFile" but bytewise
static uint8_t      dcBL_myBuf[300000]; // same content like "dcBL_AtbBinFile" but bytewise

bool dcBL_importBinFile(QByteArray readBinFile, uint32_t fileSize, char withDispl)
{
    uint16_t uitmp;
    uint32_t ultmp;
    uint32_t LL;
    QString tmpStr="", s2tmp="";

    dcBL_AtbBinFile=readBinFile;
    dcBL_fileSize=fileSize;

    //if (dcBL_fileSize>258048)       // 27.3.23TS  woher kommt die Zahl???
                                    // das hex file hat 278kB
                                    // hex file nicht erlaubt???
    if (dcBL_fileSize>=300000)
        return false;       // keep last file
    ultmp=dcBL_fileSize;
    ultmp %=64;
    uitmp=uint16_t(ultmp);
    ultmp=dcBL_fileSize;
    ultmp /=64;
    dcBL_nrOfBlocks=uint16_t(ultmp);
    if (uitmp>0)
        dcBL_nrOfBlocks++;    // letzter Block hat !=64 byte

    // type conversion for crc calc
    for (LL=0; LL<dcBL_fileSize; LL++)
        dcBL_myBuf[LL]=uint8_t(dcBL_AtbBinFile[LL]);

    dcBL_fileCrc=dcBL_calcCrcCcitt(LL, dcBL_myBuf);
//    dcBL_writeText("file crc calculated successful");

    if (withDispl)
    {
        s2tmp="crc: ";
        tmpStr.setNum(dcBL_fileCrc,16);
        s2tmp.append(tmpStr);
        dcBL_writeText(s2tmp);

        tmpStr.clear();
        s2tmp="blocks: ";
        tmpStr.setNum(dcBL_nrOfBlocks,10);
        s2tmp.append(tmpStr);
        dcBL_writeText(s2tmp);

        tmpStr.clear();
        s2tmp="last block size: ";
        tmpStr.setNum(uitmp,10);
        s2tmp.append(tmpStr);
        dcBL_writeText(s2tmp);
    }
    return true;

// erstmal nicht wie bisher um 14 Bytes nach oben schieben und Laenge/crc anhaengen,
//    weil man sonst den BL und das Win-tool auch aendern muesste

}

char dcBL_loadBinSafe(void)
{
    // retval: true: file = OK
    // Problem: nach der BL Programmierung ist das flash sehr oft defekt (ganze Bereiche sind falsch)
    // die Übertragung ist CRC geschüzt, also bleibt die Vermutung das es am Einlesen des binfiles liegt.
    // --->also sicherstellen dass das Laden des Binfiles 100%ig in Ordnung ist.
    QByteArray BINFILECOPY1, BINFILECOPY2, BINFILECOPY3;
    uint32_t   BinFileCpyLen1, BinFileCpyLen2, BinFileCpyLen3, LL;
    uint8_t    repeat=0, nn=0, stopp=0;
    //char        cc;

    do
    {
        //dcBL_writeText("loading 1st time:");
        //qDebug() <<"loading 1st time:";
        dcBL_loadBinary(0);
        // file jetzt in: "QByteArray dcBL_AtbBinFile" mit Laenge "uint32_t dcBL_fileSize"
        BINFILECOPY1=dcBL_AtbBinFile;
        BinFileCpyLen1=dcBL_fileSize;

        //dcBL_writeText("loading 2nd time:");
        //qDebug() <<"loading 2. time:";
        dcBL_loadBinary(0);
        // file jetzt in: "QByteArray dcBL_AtbBinFile" mit Laenge "uint32_t dcBL_fileSize"
        BINFILECOPY2=dcBL_AtbBinFile;
        BinFileCpyLen2=dcBL_fileSize;

        //dcBL_writeText("loading 3rd time:");
        //qDebug() <<"loading 3. time:";
        dcBL_loadBinary(0);
        // file jetzt in: "QByteArray dcBL_AtbBinFile" mit Laenge "uint32_t dcBL_fileSize"
        BINFILECOPY3=dcBL_AtbBinFile;
        BinFileCpyLen3=dcBL_fileSize;

//cc=BINFILECOPY2[100];
//if (cc>0)
//    BINFILECOPY2[100]=0;
//else
//    BINFILECOPY2[100]=1;

        repeat=0;
        if (BinFileCpyLen1 !=BinFileCpyLen2 || BinFileCpyLen1 !=BinFileCpyLen3)
        {
            dcBL_writeText("file length wrong");
            qDebug() <<"length error";

            repeat=1;       // load both again....
        }
        if (repeat==0)
        {
            LL=0; stopp=0;
            //qDebug() <<"1. loop";

            do
            {
                if (dcBL_AtbBinFile[LL] != BINFILECOPY1[LL])
                    stopp=1;
            } while((++LL < dcBL_fileSize) && !stopp);

            if (stopp)
            {
                dcBL_writeText("file compare1 wrong ");
                repeat=1;       // load both again....
            }
        }

        if (repeat==0)
        {
            LL=0; stopp=0;
            //qDebug() <<"2. loop";
            do
            {
                if (dcBL_AtbBinFile[LL] != BINFILECOPY2[LL])
                    stopp=1;
            } while((++LL < dcBL_fileSize) && !stopp);

            if (stopp)
            {
                dcBL_writeText("file compare2 wrong ");
                repeat=1;       // load both again....
            } else
                dcBL_writeText("file OK");
        }

    } while (++nn<3 && repeat);     // 3 trials

    qDebug() << "compare finito " << nn << " " << repeat;

    if (repeat==0)
        return true;    // file OK
    return false;       // error, could not load correctly

}




uint8_t dcBL_getAtbFileHeader(uint8_t *buf)
{
    // this header is prepended by the pc-direct-loader-tool
    //  (so the uC-BL expects this!) here it is sent seperately:
    uint8_t myBuf[30], pp=0, len;

    myBuf[pp++]='A';
    myBuf[pp++]='T';
    myBuf[pp++]='B';
    myBuf[pp++]='-';
    myBuf[pp++]='D';
    myBuf[pp++]='C';
    myBuf[pp++]='2';
    myBuf[pp++]='-';
    myBuf[pp++]=ulongTOuchar(dcBL_fileSize, GETHIGHBYTE);
    myBuf[pp++]=ulongTOuchar(dcBL_fileSize, GETMIDHIGHBYTE);
    myBuf[pp++]=ulongTOuchar(dcBL_fileSize, GETMIDLOWBYTE);
    myBuf[pp++]=ulongTOuchar(dcBL_fileSize, GETLOWBYTE);
    myBuf[pp++]='-';
    myBuf[pp++]=uintTOuchar(dcBL_fileCrc, GETHIGHBYTE);
    myBuf[pp++]=uintTOuchar(dcBL_fileCrc, GETLOWBYTE);
    myBuf[pp++]='-';
    len=pp;
    //tslib_strcpy(myBuf, buf, (len+3));
    len=dcBL_prepareDC_BLcmd(0x32, len, myBuf, buf);
    return len;
}

uint8_t dcBL_getFileBlock(uint16_t blockPointer, uint8_t *buf)
{
    // blockPointer=0....4095
    uint32_t addr, LL;  //, BL;
    //uint8_t  uit8tmp;
    //QString stemp=" ";

    addr=uint32_t(blockPointer);
    addr<<=6;   // *64  =Start address
/*
    if ( (addr+63)>dcBL_fileSize)
    {
        BL=dcBL_fileSize-addr+1;      // Block Length
        for (LL=0; LL<64; LL++)
            buf[LL]=0;
        if (BL>64) BL=64;               // security limitation
        // only BL bytes are left to give
        for (LL=0; LL<BL; LL++)
        {
            buf[LL]=uint8_t(dcBL_AtbBinFile[LL+addr]);
            // buf[LL]=dcBL_myBuf[LL+addr];
        }
        return uint8_t(BL);
    } else
    */
    {
        // all 64bytes can be read:
        for (LL=0; LL<64; LL++)
        {
            buf[LL]=uint8_t(dcBL_AtbBinFile[LL+addr]);
            //buf[LL]=dcBL_myBuf[LL+addr];
        }

/*
        // Kontrolle:
        qDebug()<<"dcBL getFileBlock myBuf: ";
        int ii=0;
        do
        {
            uit8tmp=(uint8_t)dcBL_myBuf[ii++];
            //qDebug() << uit8tmp << " "; // Anzeige in dez
            stemp.setNum(uit8tmp,16);
            qDebug() << stemp << " ";   // Anzeige in hex

        } while (ii<64);

        qDebug()<<"dcBL getFileBlock myBuf: ";
        ii=0;
        do
        {
            uit8tmp=(uint8_t)buf[ii++];
            //qDebug() << uit8tmp << " "; // Anzeige in dez
            stemp.setNum(uit8tmp,16);
            qDebug() << stemp << " ";   // Anzeige in hex

        } while (ii<64);
*/

        return 64;
    }
    //return 0;
}



// -----------------------------------------------------------------------------------------------
// --   fully automatic programmimg chain  ------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------

// use modules above and this functions from PI:
// sendWRcmd_setSendBlock160(len, buf);
// epi_getRawRecLength();
// epi_getRawReceivedData(receivedData);



// this lines shall be displayed in tabFW / FW_responseWindow
// they are read every 100ms. Make batch for 10 lines
#define SIZEBLRESP      50
static QString BlResp[SIZEBLRESP];
static int     pBlResp;

bool dcBL_isTextMemFree(void)
{
    if (pBlResp<0) pBlResp=0;       // just for security
    if (pBlResp<(SIZEBLRESP-1))
        return true;
    return false;
}

void dcBL_writeText(QString newTxt)
{
    // write text her in this file from memory 1....9, mem 0 is always free
    if (dcBL_isTextMemFree())
        BlResp[++pBlResp]=newTxt;
}

bool dcBL_checkForText(void)
{
    // if pointer at 0 then no more content
    if (pBlResp>0)
        return true;
    return false;
}

QString dcBL_readText(void)
{
    // read from 0...9 (oldest first)
    if (pBlResp<=0)     // should never be <0
        return "";
    QString locStr=BlResp[1];       // store memory[1]

    // move memories down by one: 2->1 3->2 4>3....9->8. Place 1 is free now
    // example: if pBlResp==3 then we have still text 2 and 3 to display. 1 will be transfered now with  this call
    int nn;
    for (nn=1; nn<pBlResp; nn++)
        BlResp[nn]=BlResp[nn+1];
    if (pBlResp>0) pBlResp--;
    return locStr;
}



// -------------------------------------------------------------------------


static uint8_t dcBL_step, dcBL_state;
static uint16_t dcBL_BlkCtr, dcBL_cyclCtr, repeatCtr;

void dcBL_iniChain(void)
{
    int nn;
    dcBL_step=0;
    dcBL_cyclCtr=0;
    dcBL_state=0;
    dcBL_BlkCtr=0;
    repeatCtr=0;

    // delete output window:
    pBlResp=0;
    for (nn=0;nn<SIZEBLRESP; nn++)
        BlResp[nn]="";
    //dcBL_writeText("**CLEAR**");
    dcBL_writeText("bl chain ini");
}

uint8_t dcBL_startChain(void)
{
    if (dcBL_step==0 || dcBL_step>17)
    {
        dcBL_iniChain();
        dcBL_step=1;
        //epi_clrRawReceivedString();
        qDebug()<<"starting chain...";
        //qDebug()<<pBlResp;
        dcBL_writeText("bl chain start");
    }
    return 0;
}


uint8_t dcBL_runChain(void)
{
    // starting BL
    // request BL-version (to be sure it's working)
    // send start address
    // send bin-file
    // check all responses
    // display result
    // close BL

    // sequencer, triggered by 100ms timer from mainwindow over TabFw::updateGui

    QString tmpStr="";

    uint8_t buf[70], sendBuf[160], len, sendLen, gotResp, ii, uit8tmp;
    //static uint8_t lastBlkLength;
    QString stemp=" ";
    uint32_t ultmp;
    bool ret;
    //uint8_t recLen, recBuff[160], ;

   gotResp=dcBL_ChkResponse();  //zum test hier raus, unten gehts nicht, darf nur 1x

    switch (dcBL_step)
    {
        case 1: // tell DC-app to restart
            dcBL_writeText("loading binary..");
            ret=dcBL_loadBinSafe();
            if (ret)
                dcBL_step++;
            else
            {
                dcBL_writeText("cancel, cannot load binary!");
                dcBL_step=0;
            }
            break;

        case 2:
            dcBL_writeText("sending restart...");
            len=dcBL_restartDC(buf);
            sendWRcmd_setSendBlock160(len, buf);
            dcBL_step++;
            break;

        case 3: // wait 100ms more
            dcBL_step++;
            break;

        case 4: // start BL
            dcBL_writeText("sending BL start...");
            len=dcBL_activatBootloader(buf);
            sendWRcmd_setSendBlock160(5, buf);
            dcBL_step++;
            dcBL_cyclCtr=0;
            break;

        case 5: // wait for answer: 2 99 52 53 98 51 3
        // Problem: kommt von app, nicht vom BL. Also wenn BL schon aktiv ist dann gehts nicht

            /*
            dcBL_cyclCtr++;
            if (recLen>6 && recBuff[0]==2 && recBuff[1]==99 && recBuff[2]==52)
               // && recBuff[3]==53 && recBuff[4]==98 && recBuff[5]==51 && recBuff[6]==3 )
            {
                dcBL_writeText("BL started");
                dcBL_cyclCtr=0;
                dcBL_step++;
                return 0;
            }
            //qDebug()<<dcBL_cyclCtr;
            if (dcBL_cyclCtr>10)    // 50 gibt 6,2s
            {
                // cancel, report error
                dcBL_writeText("cannot start BL, cancel");
                dcBL_state=3;
                dcBL_step=0;    // stop chain
                return 0;
            } */

            dcBL_step++;
            repeatCtr=0;
            break;

        case 6: // request Version number
            len=dcBL_readFWversion(buf);
            sendWRcmd_setSendBlock160(len, buf);
            dcBL_writeText("request version nr...");
            dcBL_cyclCtr=0;
            dcBL_step++;
            break;

        case 7: // wait for answer  2 146 45 45 95 176 3

            if (gotResp==ISOK)
            {
                dcBL_state=1;   // BL started
                dcBL_step++;
                repeatCtr=0;
                return 0;
            } else
            if (gotResp==ISWRONG)
            {
                if (++repeatCtr<3)
                {
                    dcBL_step--;
                }else
                {
                    dcBL_step=0;    // stop chain
                }
            }

            if (++dcBL_cyclCtr>10)
            {
                dcBL_writeText("cancel");
                dcBL_step=0;    // stop chain
            }
            break;

        case 8: // send start address
            if (dcBL_BlkCtr==0 || dcBL_BlkCtr==1024 || dcBL_BlkCtr==2048 || dcBL_BlkCtr==3072 || dcBL_BlkCtr==4096)
            {
                ultmp=uint32_t(dcBL_BlkCtr);
                ultmp*=64;
                len=dcBL_sendFlashStartAddr2BL(ultmp, buf);
                sendWRcmd_setSendBlock160(len, buf);
                dcBL_writeText("sending start address");
                dcBL_cyclCtr=0;
                dcBL_step++;
                return 0;
            } else
                dcBL_step=12;
            break;

        case 9: // wait for answer 2 161 68 59 3
            if (gotResp==ISOK)
            {
                dcBL_step=12;   // Header nicht senden, unnötig
                dcBL_BlkCtr=0;        //  0
                repeatCtr=0;
                return 0;
            } else
            if (gotResp==ISWRONG)
            {
                if (++repeatCtr<3)
                {
                    dcBL_step--;
                } else
                {
                    dcBL_step=0;    // stop chain
                }
            }
            if (++dcBL_cyclCtr>10)
            {
                dcBL_writeText("cancel");
                dcBL_step=0;    // stop chain
            }
            break;


        case 12: // send binary 64 byte wise

            len=dcBL_getFileBlock(dcBL_BlkCtr, buf);      // read from file, len = 0...64
            //lastBlkLength=len;                          // recognize last block or end
            sendLen=dcBL_prepareDC_BLcmd(0x22, len, buf, sendBuf);   // pack into protocol frame


            // Kontrolle:
            qDebug()<<"dcBL sending: ";
            ii=0;
            do
            {
                uit8tmp=(uint8_t)sendBuf[ii++];
                //qDebug() << uit8tmp << " "; // Anzeige in dez
                stemp.setNum(uit8tmp,16);
                qDebug() << stemp << " ";   // Anzeige in hex

            } while (ii<100);


            sendWRcmd_setSendBlock160(sendLen, sendBuf);                  // send 140 bytes
            delay(100);
            //dcBL_writeText("blk nr: ");
            tmpStr.setNum(dcBL_BlkCtr);
            dcBL_writeText(tmpStr);
            delay(100);
            //qDebug()<<"sending: " << buf;
            dcBL_cyclCtr=0;
            dcBL_BlkCtr++;
            dcBL_step++;
            break;

        case 13: // wait for answer  2 162 116 88 3

            if (gotResp==ISOK)
            {
                // check if next address is needed (every 1024Blocks = 65536bytes)
                if (dcBL_BlkCtr==1024 || dcBL_BlkCtr==2048 || dcBL_BlkCtr==3072 || dcBL_BlkCtr==4096)
                {
                    dcBL_step=8;
                    return 0;
                }

                // check for EOF:
                if (dcBL_BlkCtr >= dcBL_nrOfBlocks)
                {
                    dcBL_writeText("last block successful sent...");
                    dcBL_step++;    // stop chain
                    dcBL_state=3;   // transmission SUCCESSFUL
                    return 0;
                }
                dcBL_state=2;   // transmission started
                dcBL_step--;    // send next data block
                repeatCtr=0;
                return 0;
            }
            if (gotResp==ISWRONG)
            {
                if (++repeatCtr<3)
                {
                    dcBL_writeText("error");
                    dcBL_BlkCtr--;
                    dcBL_step--;    // send same block again
                } else
                {
                    dcBL_step=0;    // stop chain
                }
            }
            if (++dcBL_cyclCtr>30)  // longer TO due to flashing
            {
                dcBL_writeText("cancel");
                dcBL_step=0;    // stop chain
            }
            break;

        case 14: //
            dcBL_writeText("finish writing flash");
            len=dcBL_writeLastPage(buf);        // nur zur Sicherheit
            sendWRcmd_setSendBlock160(len, buf);
            dcBL_step++;
            break;

        case 15: // wait for answer
            if (gotResp==ISOK)
            {
                dcBL_step++;
                repeatCtr=0;
                return 0;
            } else
            if (gotResp==ISWRONG)
            {
                if (++repeatCtr>3)
                {
                    dcBL_step--;
                }
            }
            if (++dcBL_cyclCtr>10)
            {
                dcBL_writeText("cancel");
                dcBL_step=0;    // stop chain
            }
            break;


        case 16: //
            dcBL_writeText("exit BL, bye");
            len=dcBL_exitBL(buf);
            sendWRcmd_setSendBlock160(len, buf);
            dcBL_step++;

            break;

        case 17: // wait for answer, not sure if it comes!
            if (gotResp==ISOK)
            {
                dcBL_step++;
                repeatCtr=0;
                return 0;
            } else
            if (gotResp==ISWRONG)
            {
                if (++repeatCtr>10)
                {
                    dcBL_step--;
                }
            }
            if (++dcBL_cyclCtr>30)
            {
                dcBL_writeText("cancel");
                dcBL_step=0;    // stop chain
            }
            break;

        case 18:
            dcBL_step=0;
            break;
    }

    return 0;
}



void dcBL_iniLoading(void)
{
    dcBL_iniChain();
}


// nicht verwendet
void dcBL_startLoading(void)
{
    if (dcBL_step==0 || dcBL_step>17)
    {
        //dcBL_iniChain();
        dcBL_step=1;
        //epi_clrRawReceivedString();
        qDebug()<<"DCBL start sending hexfile...";
        dcBL_writeText("DCBL start sending hexfile...");
        dcBL_BlkCtr=0;
        dcBL_cyclCtr=0;
    }

}


// nicht verwendet
uint8_t dcBL_sendHexfile(void)
{
    QString tmpStr="";
    uint8_t buf[70], sendBuf[160], len, sendLen, gotResp;   //, recLen; recBuff[160], ii,
    QString stemp=" ";
    uint32_t ultmp;
    //uint8_t uit8tmp, ii;


    gotResp=dcBL_ChkResponse();

    switch (dcBL_step)
    {
        case 1: // send start address
            if (dcBL_BlkCtr==0 || dcBL_BlkCtr==1024 || dcBL_BlkCtr==2048 || dcBL_BlkCtr==3072 || dcBL_BlkCtr==4096)
            {
                ultmp=uint32_t(dcBL_BlkCtr);
                ultmp*=64;
                len=dcBL_sendFlashStartAddr2BL(ultmp, buf);
                sendWRcmd_setSendBlock160(len, buf);
                qDebug()<<" DCBL_CYCL_sending HexFile address ";
                dcBL_writeText("sending addr");
                dcBL_step++;
                return 0;
            } else
                dcBL_step=12;
            break;

        case 2: // wait for answer 2 161 68 59 3
            if (gotResp==ISOK)
            {
                dcBL_step=12;   // Header nicht senden, unnötig
                dcBL_BlkCtr=0;        //  0
                repeatCtr=0;
                return 0;
            } else
            if (gotResp==ISWRONG)
            {
                if (++repeatCtr<3)
                {
                    dcBL_step--;
                } else
                {
                    dcBL_step=0;    // stop chain
                    qDebug()<<" DCBL_CYCL_got wrong resp to addr";
                    dcBL_writeText("wrong resp");
                }
            }
            if (++dcBL_cyclCtr>100)
            {
                dcBL_writeText("cancel");
                 qDebug()<<" DCBL_CYCL_step 2  got NO resp to addr";
                dcBL_step=0;    // stop chain
            }
            break;

        case 12: // send binary 64 byte wise

            len=dcBL_getFileBlock(dcBL_BlkCtr, buf);      // read from file, len = 0...64
            //lastBlkLength=len;                          // recognize last block or end
            sendLen=dcBL_prepareDC_BLcmd(0x22, len, buf, sendBuf);   // pack into protocol frame
/*
            // Kontrolle:
            qDebug()<<"dcBL sending: ";
            ii=0;
            do
            {
                uit8tmp=(uint8_t)sendBuf[ii++];
                //qDebug() << uit8tmp << " "; // Anzeige in dez
                stemp.setNum(uit8tmp,16);
                qDebug() << stemp << " ";   // Anzeige in hex

            } while (ii<100);
*/
            sendWRcmd_setSendBlock160(sendLen, sendBuf);                  // send 140 bytes
            delay(100);
            dcBL_writeText("blk nr: ");
            tmpStr.setNum(dcBL_BlkCtr);
            dcBL_writeText(tmpStr);
            delay(100);
            qDebug()<<"DCBL sending blk nr: " << dcBL_BlkCtr;
            dcBL_cyclCtr=0;
            dcBL_BlkCtr++;
            dcBL_step++;
            break;

        case 13: // wait for answer  2 162 116 88 3

            if (gotResp==ISOK)
            {
                // check if next address is needed (every 1024Blocks = 65536bytes)
                if (dcBL_BlkCtr==1024 || dcBL_BlkCtr==2048 || dcBL_BlkCtr==3072 || dcBL_BlkCtr==4096)
                {
                    dcBL_step=8;
                    return 0;
                }

                // check for EOF:
                if (dcBL_BlkCtr >= dcBL_nrOfBlocks)
                {
                    dcBL_writeText("last block successful sent...");
                    dcBL_step++;    // stop chain
                    dcBL_state=3;   // transmission SUCCESSFUL
                    return 0;
                }
                dcBL_state=2;   // transmission started
                dcBL_step--;    // send next data block
                repeatCtr=0;
                return 0;
            }
            if (gotResp==ISWRONG)
            {
                if (++repeatCtr<3)
                {
                    dcBL_writeText("error");
                    dcBL_BlkCtr--;
                    dcBL_step--;    // send same block again
                } else
                {
                    dcBL_step=0;    // stop chain
                }
            }
            if (++dcBL_cyclCtr>30)  // longer TO due to flashing
            {
                dcBL_writeText("cancel");
                dcBL_step=0;    // stop chain
            }
            break;

        case 14: //
            dcBL_writeText("finish writing flash");
            len=dcBL_writeLastPage(buf);        // nur zur Sicherheit
            sendWRcmd_setSendBlock160(len, buf);
            dcBL_step++;
            break;

        case 15: // wait for answer
            if (gotResp==ISOK)
            {
                dcBL_step++;
                repeatCtr=0;
                return 0;
            } else
            if (gotResp==ISWRONG)
            {
                if (++repeatCtr>3)
                {
                    dcBL_step--;
                }
            }
            if (++dcBL_cyclCtr>10)
            {
                dcBL_writeText("cancel");
                dcBL_step=0;    // stop chain
            }
            break;

    }
    return 0;
}





uint8_t dcBL_getResult(void)
{
    // call after every step to what's going on....
    //  1: connected to BL
    //  2: transmission started
    //  3: transmission successful

    return dcBL_state;
}

// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------


static uint8_t Sdata_rawData[RAW_BL_DATALEN];

static uint8_t Sdata_LengthRawData;

void gpi_storeRawReceivedData(uint8_t  RdDlen, uint8_t *receivedData)
{
    uint8_t nn;
    Sdata_LengthRawData=RdDlen;
    if (Sdata_LengthRawData>RAW_BL_DATALEN)
        Sdata_LengthRawData=RAW_BL_DATALEN;
    for (nn=0; nn<Sdata_LengthRawData; nn++)
        Sdata_rawData[nn]=receivedData[nn];
    //qDebug()<<"dcBL got data"<<  Sdata_LengthRawData << "bytes :)";

}

uint8_t epi_getRawReceivedData(uint8_t *receivedData)
{
    // retval=length, will be zeroed after first reading
    uint8_t nn, ret;

    for (nn=0; nn<Sdata_LengthRawData; nn++)
        receivedData[nn]=Sdata_rawData[nn];
    ret=Sdata_LengthRawData;
    //Sdata_LengthRawData=0;
    return ret;
}

uint8_t epi_getRawRecLength(void)
{
    // retval=length
    return Sdata_LengthRawData;
}

QString epi_getRawReceivedString()
{
    uint8_t nn;     //, ret;
    QString myString=nullptr, tmpStr=nullptr;

    myString.clear();
    if (Sdata_LengthRawData==0)
        return myString;

    for (nn=0; nn<Sdata_LengthRawData; nn++)
    {
        tmpStr.clear();
        tmpStr.setNum(Sdata_rawData[nn],16);   // problem: wenn >0x80 dann wird EIN Byte 16 stellig angezeigt
        int ll=tmpStr.length();
        if (ll>2)
        {
            myString.append(tmpStr[ll-2]);
            myString.append(tmpStr[ll-1]);
        } else
        {
            myString.append(tmpStr);
        }
            myString.append(" ");

    }
    //ret=Sdata_LengthRawData;
    //Sdata_LengthRawData=0;
    return myString;
}

void epi_clrRawReceivedString()
{
    Sdata_LengthRawData=0;
}









