//#include <stdio.h>
//#include <stdlib.h>
//#include <malloc.h>
#include <string.h>
#include <windows.h>

#ifndef _COMM_
#include "comm.h"
#endif

#ifndef _PVTASK_
#include "pvtask.h"
#endif

#ifndef _SD_ABI_DEF_
#include "sdabidef.h"
#endif

#ifndef _ABI_FUNC_
#include "abifunc.h"
#endif

#ifndef _COMMUNICATION_
#include "comm.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

/* from windows.h for Windows 3.1 */
#ifndef HFILE
typedef int HFILE; /* Polymorphic with C runtime file handle type */
#define HFILE_ERROR ((HFILE)-1)
#endif

#ifndef SEEK_SET
#define SEEK_SET 0
#endif

#define ACK 6
#define NACK 0x15
#define ESC 0x1b
#define LINK_TIMEOUT 5000

U8 BASE_TIME;
extern int portId;
extern U16 printerPort;
/**************************************************************************
**
** Name : CheckFwStatus
**
** Function
**        Check the status of MICEpack. MICEpack have "COLD START", "NORMAL"
**        and "DIAGNOSTIC" status. the other status is not normal.
**
**    Input  :
**       None
**    Output :
**       None
** Notes:
**
**************************************************************************/
RETCODE EXPORT CheckFwStatus(VOID) {
U8 idData[MAX_ID];
int i, retID;
DWORD startTime;

   while (1) {
      startTime = GetCurrentTime();

      while ((GetCurrentTime()-startTime) < LINK_TIMEOUT) {

         if (chk_hlt() == ESC) return(ICE_HALT_USER); // check keyboard.
         // Ken, Replace chk_hlt() to your program . Allen.
         if (sendB('M') != GOOD) continue;
         if (sendB('I') != GOOD) continue;
         if (sendB('C') != GOOD) continue;
         if (sendB('E') != GOOD) continue;
         i = receiveB();
         if (i == ACK) {
            return(COLD_START);
         } else if (i == ':') {
            iceGetID(idData);
            if (idData[0] == 'D') return(DIAGNOSTIC_STATUS);
            else return(NORMAL_STATUS);
         } else if (i == '?') {
            return(HW_RESET_STATUS);
         }
      }
      ErrMessageBox((LPSTR)"MICEpack/SLD",(LPSTR)"MICEpack/SLD link MICE fail !!",
            MB_RETRYCANCEL | MB_ICONASTERISK,0,
            (S16 FAR *)&retID);   // gene*
      if (retID == IDCANCEL) break;
   }
   return(ICE_LINK_MICE_FAIL);
}
/**************************************************************************
**
** Name :
**
** Function
**
**    Input  :
**
**    Output :
**
** Notes:
**
**************************************************************************/
//#define FILE_SIZE     255
#define BUFF_UNIT     1024 // basic buffer unit.

U16 fileSize;

RETCODE EXPORT DownLoadFirmwareParallel(U8 *fileName,U16 buffSize,U8 timeOut);
RETCODE EXPORT DownLoadFirmwareSerial(U8 *fileName,U16 buffSize,U8 timeOut);

RETCODE EXPORT DownLoadFirmware(U8 *fileName,U16 buffSize,U8 timeOut) {

   if (strnicmp(fileName,"main",4) == 0)
      fileSize = 255;
   else
      fileSize = 127;
//   fileSize = 255;
   if (printerPort == 2)
      return(DownLoadFirmwareSerial(fileName,buffSize,timeOut));
   else
      return(DownLoadFirmwareParallel(fileName,buffSize,timeOut));
}

RETCODE EXPORT DownLoadFirmwareParallel(U8 *fileName,U16 buffSize,U8 timeOut) {
U8 dataBuff[0x400],blockNo,firstBlock; // basic unit : 1K.
S32 filePos;
S16 lp,lp3,lp5,aa,buffLen;
S32 count;
HFILE fStream;
U32 startAddr;
RETCODE status;


   if ((buffSize = (buffSize/BUFF_UNIT)) == 0) buffSize = 1; // Set buffer size. Minimum 1K.
//   if (firstBlock = FILE_SIZE % buffSize) blockNo = (FILE_SIZE/buffSize)+1;
   if (firstBlock = fileSize % buffSize) blockNo = (fileSize/buffSize)+1;
   else {
//      blockNo = (FILE_SIZE/buffSize);
      blockNo = (fileSize/buffSize);
      firstBlock = buffSize;
   }
   if ((fStream = _lopen(fileName,READ)) == HFILE_ERROR) {
      status = SendAddrLen(0L,0L); // Notify MICEpack re-download.
      return(ICE_FILE_NOT_FOUND);
   }
   for (lp5 = 0; lp5 < 5; lp5++) { // Try 5 times. If download failed, return failed.
      filePos = 0;
      startAddr = 0x400;
      for (lp = 0; lp < blockNo; lp++) {
         (lp) ? (buffLen = buffSize) : (buffLen = firstBlock);
         buffLen *= BUFF_UNIT; // each transmit buffer size.
         status = SendAddrLen(startAddr,buffLen);
         startAddr += buffLen;
         if (status != GOOD) { // if the data of address and length download fail. Re-download them.
            lp--;
            startAddr -= buffLen;
            continue;
         }
         do {
            if ((aa = receiveWait(timeOut)) == ICE_TIME_OUT) {
               return(ICE_TIME_OUT);
            }
         } while ((aa != ACK) && (aa != NACK));
         if (aa == NACK) {
            lp--;
            startAddr -= buffLen;
            continue;
         }
         count = _lread(fStream,(void _huge*)dataBuff,buffLen);
         for (lp3 = 0; lp3 < count; lp3++)
            if ((aa = sendB(dataBuff[lp3])) != GOOD) break;
         if (aa != GOOD) {
            lp--;
            startAddr -= (buffLen);
            continue;
         }
         do {
            if ((aa = receiveWait(timeOut)) == ICE_TIME_OUT) {
               return(ICE_TIME_OUT);
            }
         } while ((aa != ACK) && (aa != NACK));
         if (aa == NACK) {
            _llseek(fStream,filePos,SEEK_SET);
            lp--;
            startAddr -= buffLen;
         }
         else filePos += (U32)buffLen;
      }
      SendAddrLen(0l,0l);
      _lclose(fStream);
      do {
         if ((aa = receiveWait(timeOut)) == ICE_TIME_OUT) {
            return(ICE_TIME_OUT);
         }
      } while ((aa != ACK) && (aa != NACK));
      if (aa == ACK) break;
   }
   return(GOOD);
}

RETCODE EXPORT DownLoadFirmwareSerial(U8 *fileName,U16 buffSize,U8 timeOut) {
U8 dataBuff[0x400],blockNo,firstBlock; // basic unit : 1K.
S32 filePos;
S16 lp,lp3,lp5,aa,buffLen;
S32 count;
HFILE fStream;
U32 startAddr;
RETCODE status;
U32 checksumLen;
U16 checksum;


   if ((buffSize = (buffSize/BUFF_UNIT)) == 0) buffSize = 1; // Set buffer size. Minimum 1K.
//   if (firstBlock = FILE_SIZE % buffSize) blockNo = (FILE_SIZE/buffSize)+1;
   if (firstBlock = fileSize % buffSize) blockNo = (fileSize/buffSize)+1;
   else {
//      blockNo = (FILE_SIZE/buffSize);
      blockNo = (fileSize/buffSize);
      firstBlock = buffSize;
   }
   if ((fStream = _lopen(fileName,READ)) == HFILE_ERROR) {
      status = SendAddrLen(0L,0L); // Notify MICEpack re-download.
      return(ICE_FILE_NOT_FOUND);
   }
   for (lp5 = 0; lp5 < 5; lp5++) { // Try 5 times. If download failed, return failed.
      filePos = 0;
      startAddr = 0x400;
      for (lp = 0; lp < blockNo; lp++) {
         if (printerPort == 2) {
            FlushComm(portId,0);
            FlushComm(portId,1);
         }
         (lp) ? (buffLen = buffSize) : (buffLen = firstBlock);
         buffLen *= BUFF_UNIT; // each transmit buffer size.
         count = _lread(fStream,(void _huge*)dataBuff,buffLen);
         checksum = 0;
         for (lp3 = 0; lp3 < count; lp3++)
            checksum += dataBuff[lp3];
//         checksum = ~checksum + 1;
         checksumLen = (((U32)checksum) << 16) + (U32)buffLen;
         status = SendAddrLen(startAddr,checksumLen);
         startAddr += buffLen;
         if (status != GOOD) { // if the data of address and length download fail. Re-download them.
            lp--;
            startAddr -= buffLen;
            continue;
         }
         do {
            if ((aa = receiveWait(timeOut)) == ICE_TIME_OUT) {
               return(ICE_TIME_OUT);
            }
         } while ((aa != ACK) && (aa != NACK));
         if (aa == NACK) {
            lp--;
            startAddr -= buffLen;
            _llseek(fStream,filePos,SEEK_SET);
            continue;
         }
         for (lp3 = 0; lp3 < count; lp3++)
            if ((aa = sendB(dataBuff[lp3])) != GOOD) break;
         if (aa != GOOD) {
            lp--;
            startAddr -= (buffLen);
            _llseek(fStream,filePos,SEEK_SET);
            continue;
         }
         do {
            if ((aa = receiveWait(timeOut)) == ICE_TIME_OUT) {
               return(ICE_TIME_OUT);
            }
         } while ((aa != ACK) && (aa != NACK));
         if (aa == NACK) {
            _llseek(fStream,filePos,SEEK_SET);
            lp--;
            startAddr -= buffLen;
         }
         else filePos += (U32)buffLen;
      }
      SendAddrLen(0l,0l);
      _lclose(fStream);
      do {
         if ((aa = receiveWait(timeOut)) == ICE_TIME_OUT) {
            return(ICE_TIME_OUT);
         }
      } while ((aa != ACK) && (aa != NACK));
      if (aa == ACK) break;
   }
   return(GOOD);
}

/**************************************************************************
**
** Name :
**
** Function
**
**    Input  :
**
**    Output :
**
** Notes:
**
**************************************************************************/

RETCODE EXPORT linkMICE(INITIAL_INFO *initialInfo) {

   DownLoadFirmware(initialInfo->fileName,0x400,0xff);
   return (GOOD);
}   // end of linkMice()

/**************************************************************************
**
** Name :
**
** Function
**
**    Input  :
**
**    Output :
**
** Notes:
**
**************************************************************************/

RETCODE EXPORT iceInitialize(INITIAL_INFO *initialInfo) {
S16 status;
//S16 status2;
//U16 lp, testSeq[] = { MCE16A, EMM1, EMM2, EMM3, EMM4, TRACE_BOARD};
//U8 idData[MAX_ID]
U8 retID;
U32 memFailAddress;

   BASE_TIME = initialInfo->timeOut;
   SetComm(initialInfo->portAddr);
   status = CheckFwStatus();
   switch (status) {
      case DIAGNOSTIC_STATUS :
         DiagnosticFunction(END_DIAG, &memFailAddress,&retID);
         CheckFwStatus();
         status = linkMICE(initialInfo); // for cold start and diagnostic
         break;
      case COLD_START :
         status = linkMICE(initialInfo); // for cold start and diagnostic
         break;
      case NORMAL_STATUS :
      case HW_RESET_STATUS :
         status = ICE_WARN_START;
   }
   if (status == GOOD) { // COLD_START and download OK.
/*      if (initialInfo->testFlag == TRUE) {
         for (lp = 0; lp < sizeof(testSeq)/sizeof(testSeq[0]); lp++) {
            if (chk_hlt() == ESC) break;
            status2 = iceSelfTest(testSeq[lp]);
            switch (status2) {
               case GOOD :
                  break;
               case ICE_NO_EMM :
                  initialInfo->testResult |= 4; // No EMM.
                  lp = 5;
                  break;
               case ICE_NO_TRACE_MODULE :
                  initialInfo->testResult |= 2; // No EMM.
                  break;
               default :
                  switch (lp) {
                     case 0 :
                        initialInfo->testResult |= 0x10; // MCE16A failed
                        break;
                     case 1: case 2: case 3: case 4:
                        initialInfo->testResult |= 8; // EMM failed
                        break;
                     case 5 :
                        initialInfo->testResult |= 1; // MTAT failed
                  }
            }
         }
         iceSelfTest(END_TEST);
      }
      else iceSelfTest(END_TEST);
 */
   }
   return(status);
}



