#include <stdio.h>
#include <stdlib.h>
//#include <dos.h>
#include <time.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 _SDTEMPL_
#include "sdtempl.h"
#endif

#ifndef _ERRHELP_
#include "..\errtext\errhelp.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

extern int portId;
extern U16 printerPort;
extern COMSTAT commStat;
extern U8 portName[5][5];
extern DOUBLE freqTimes;
extern testBaudrate[];

#define LINK_RETRY 15
#define LinkTimeOut 2000 // millisecond

#define INI_FILENAME "micepack.ini"
#define INI_SECTION_NAME "Baud"
#define INI_BDM_SPEED "bdmSpeed"
#define INI_KEY_NAME "Rate"

VOID TestABI();
RETCODE ComError(int curComId, COMSTAT *comStatus);
RETCODE MapComError(S16 commErr);
/**************************************************************************
**
** 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];
CHAR buf[20], *endPtr;
int i, lp2, retID;
BOOLEAN LinkOK[8],flagFinal;
DCB comDcb;
DWORD startTime,currentTime;
U16 MaxRate;
S32 curRate;


   switch (printerPort) {
   case 2:
      GetPrivateProfileString(INI_SECTION_NAME, "LinkRate", "576", buf,
         sizeof(buf), INI_FILENAME);
      curRate = strtol(buf,&endPtr,16);
      GetPrivateProfileString(INI_SECTION_NAME, "MaxRate", "576", buf,
         sizeof(buf), INI_FILENAME);
      MaxRate = atoi(buf);
      switch (MaxRate) {
      case 96:
         MaxRate = CBR_9600; break;
      case 192:
         MaxRate = CBR_19200; break;
      case 384:
         MaxRate = CBR_38400; break;
      case 576:
         MaxRate = CBR_56000; break;
      case 1152:
         MaxRate = CBR_128000; break;
      default:
         MaxRate = CBR_56000; break;
      }
      while (1) {
         flagFinal = FALSE;
         for(lp2=0; lp2<=6; lp2++) {
            startTime = GetCurrentTime();
            LinkOK[lp2] = FALSE;
            while (1) {
               if (chk_hlt() == ESC) return(ICE_HALT_USER); // check keyboard.
               // Ken, Replace chk_hlt() to your program . Allen.
               if (printerPort == 2) {
                  FlushComm(portId,0);
                  FlushComm(portId,1);
               }
               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) {
                  LinkOK[lp2] = TRUE;
                  break;
               }
               currentTime = GetCurrentTime();
               if ((currentTime - startTime) > LinkTimeOut)
                  break;
            }
            if ((flagFinal && LinkOK[lp2]) ||
                (((U16)curRate == MaxRate) && LinkOK[lp2]) ||
                ((lp2 == 0) && LinkOK[0])) {
               sendB(NACK);
               ltoa(curRate,buf,16);
               WritePrivateProfileString(INI_SECTION_NAME, "LinkRate", buf,
                   INI_FILENAME);
               return(COLD_START);
            }

            switch(lp2) {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
               if (LinkOK[lp2])
                  sendB(ACK);
               if (GetCommState(portId,(DCB FAR *) &comDcb) < 0) {
                  CloseComm(portId);
                  return(ICE_LINK_MICE_FAIL);
               }
               curRate = comDcb.BaudRate = testBaudrate[lp2+1];
               startTime = GetCurrentTime();
               do {
                  currentTime = GetCurrentTime();
               } while ((currentTime-startTime) < 60);
               if (SetCommState((DCB FAR *) &comDcb) < 0) {
                  curRate = comDcb.BaudRate = testBaudrate[lp2];
                  SetCommState((DCB FAR *) &comDcb);
                  flagFinal = TRUE;
               }
               break;
            case 6:
               if (LinkOK[lp2]) {
                  sendB(NACK);
                  ltoa(curRate,buf,16);
                  WritePrivateProfileString(INI_SECTION_NAME, "LinkRate", buf,
                      INI_FILENAME);
                  return(COLD_START);
               }
               break;
            }
         }
         ErrMessageBox((LPSTR)"MICEpack/SLD",(LPSTR)"MICEpack/SLD link MICE fail !!",
               MB_RETRYCANCEL | MB_ICONASTERISK,HE_COMM_RETRY_EXHAUSTED,
               (S16 FAR *)&retID);   // gene*
         if (retID == IDCANCEL) break;
      }
      break;
   case 1:
   case 0:
      while (1) {
         for(lp2=0; lp2<=50; lp2++) {
            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) {
              sendB(NACK);
              return(COLD_START);
            } else if (i == ':') {
              iceGetID(idData);
              if (idData[0] == 'D') return(DIAGNOSTIC_STATUS);
              else return(NORMAL_STATUS);
            }
         }
         ErrMessageBox((LPSTR)"MICEpack/SLD",(LPSTR)"MICEpack/SLD link MICE fail !! (Printer Port)",
               MB_RETRYCANCEL | MB_ICONASTERISK,HE_COMM_RETRY_EXHAUSTED,
               (S16 FAR *)&retID);   // gene*
         if (retID == IDCANCEL) break;
      }
      break;
   }
   return(ICE_LINK_MICE_FAIL);
}
/**************************************************************************
**
** Name :
**
** Function
**
**    Input  :
**
**    Output :
**
** Notes:
**
**************************************************************************/
#define FILE_SIZE     255
#define BUFF_UNIT     1024 // basic buffer unit.

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


   if ((buffSize = (buffSize/BUFF_UNIT)) == 0) buffSize = 1; // Set buffer size. Minimum 1K.
   //if ((dataBuff = (U8 *)malloc(buffSize*BUFF_UNIT)) == NULL) {// Set buffer size.
   //   status = SendAddrLen(0L,0L); // Notify MICEpack re-download.
   //   return(-1);
   //}
   if (firstBlock = (FILE_SIZE % buffSize))
      blockNo = (FILE_SIZE/buffSize)+1;
   else {
      blockNo = (FILE_SIZE/buffSize);
      firstBlock = buffSize;
   }
//   if ((fStream = fopen((U8 far *)fileName,"rb")) == NULL) {
   if ((fStream = _lopen(fileName,READ)) == HFILE_ERROR) {
      status = SendAddrLen(0L,0L); // Notify MICEpack re-download.
      //free(dataBuff);
      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) {
           //free(dataBuff);
           return(ICE_TIME_OUT);
        }
     } while ((aa != ACK) && (aa != NACK));
     if (aa == NACK) {
        lp--;
        startAddr -= buffLen;
        continue;
     }
     //count = fread((U8 *)dataBuff,sizeof(U8),buffLen,fStream);
     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) {
           //free(dataBuff);
           return(ICE_TIME_OUT);
        }
     } while ((aa != ACK) && (aa != NACK));
     if (aa == NACK) {
        //fseek(fStream,filePos,SEEK_SET);
        _llseek(fStream,filePos,SEEK_SET);
        lp--;
        startAddr -= buffLen;
     }
     else filePos += (U32)buffLen;
      }
      SendAddrLen(0l,0l);
      //fclose(fStream);
      _lclose(fStream);
      do {
     if ((aa = receiveWait(timeOut)) == ICE_TIME_OUT) {
        //free(dataBuff);
        return(ICE_TIME_OUT);
     }
      } while ((aa != ACK) && (aa != NACK));
      if (aa == ACK) break;
   }
   // Firmware loading completed.
   //free(dataBuff);
   return(GOOD);
}

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

RETCODE EXPORT linkMICE(INITIAL_INFO *initialInfo) {
RETCODE status;
U8 idInfo[MAX_ID];

   if (initialInfo->idFlag == 0xFF) {
      status = DownLoadFirmware(initialInfo->fileName,initialInfo->buffSize,
           initialInfo->timeOut);
      if (status != GOOD) return(status);
   }
   iceGetID(idInfo);
   iceGoEpDelay(initialInfo->delay);
   freqTimes = 2048.0 / initialInfo->targetClock;
   return (GOOD);
}   // end of linkMice()

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

RETCODE EXPORT iceInitialize(INITIAL_INFO *initialInfo) {
RETCODE status;
//U16 lp, testSeq[] = { MCE16A, EMM1, EMM2, EMM3, EMM4, TRACE_BOARD};

   if (SetComm(initialInfo->portAddr) != GOOD)
      return(ICE_LINK_MICE_FAIL);
   status = CheckFwStatus();
   switch (status) {
      case DIAGNOSTIC_STATUS :
         DiagnosticFunction(END_DIAG);
         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 :
         status = ICE_WARN_START;
      case ICE_HALT_USER :
         return(status);
   }
/*   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
             // case record RAM
          }
        }
     }
     iceSelfTest(END_TEST);
      }
      else iceSelfTest(END_TEST);
   } */
//   TestABI();
//   CloseComm(portId);
   return(status);
}


/*
VOID TestABI() {
//INITIAL_INFO initInfo;
RETCODE status;
ADDR addr1,addr2;
U8 coReg[10],buff[30];
//U16 allCpuReg[REG_NO];
U32 regData,regData2,lp;
//
//   initInfo.portAddr       = 0x200;     // I/O port address.
//   initInfo.idFlag         = I80C186XL; // CPU type.
//   initInfo.buffSize       = 0x400;     // buffer size of communication
//   initInfo.testResult     = 0;         // clear data.
//   initInfo.testFlag       = ON;        // do selftest.
//   initInfo.timeOut        = 0xff;         // 3 second.
//   sprintf(initInfo.fileName,"%s","main186.bin"); // download file(include path).
//
//   status = iceInitialize(&initInfo);  // Initial MICEpack.
//
   addr1.space = SPACE_SD;
   addr1.pos = 0x400;
   status = iceFill(&addr1,0x100,"abcde",5);
   iceSetReg(M68K_REG,R_PC,0x123l); // Set AX register.
   iceSetReg(M68K_REG,R_A7,0x456l); // Set BX register.
   iceSetReg(M68K_REG,R_D0,0x789l); // Set CX register.
   iceSetReg(M68K_REG,R_SR,0x111l); // Set DX register.
//   iceGetAllReg(allCpuReg); // Get all cpu registers.
   iceStepOne();
   iceGetReg(M68K_REG,R_PC,&regData); // Set AX register.
   iceGetReg(M68K_REG,R_A7,&regData); // Set BX register.
   iceGetReg(M68K_REG,R_D0,&regData); // Set CX register.
   iceGetReg(M68K_REG,R_SR,&regData); // Set DX register.

//   iceSetReg(INTERNAL_REG,POLL,0x124); // Set POLL register.
   regData2 = 0x1234;

   for(lp = 0; lp < 20; lp++)
      buff[lp] = lp+'A';

   iceSetMemN(addr1,buff,0x10); // Fill memory form 1200:2412, length = 0x10.
   addr1.pos--;
   iceSetMemN(addr1,buff,0x10); // Fill memory form 1200:2412, length = 0x10.
   iceSetMemN(addr1,buff,0x11); // Fill memory form 1200:2412, length = 0x10.
   addr1.pos++;
   iceSetMemN(addr1,buff,0x11); // Fill memory form 1200:2412, length = 0x10.

   for(lp = 0; lp < 20; lp++)
      buff[lp] = 0xff;
   iceGetMemN(addr1,buff,0x10);// Get memory from 1200:0400, length = 0x20.
   addr1.pos--;
   iceGetMemN(addr1,buff,0x10);// Get memory from 1200:0400, length = 0x20.
   iceGetMemN(addr1,buff,0x11);// Get memory from 1200:0400, length = 0x20.
   addr1.pos++;
   iceGetMemN(addr1,buff,0x11);// Get memory from 1200:0400, length = 0x20.
   iceSetBP(10,addr1);
   iceSetBP(11,addr1);
} 
*/
