/***************************************************************************
**
**    $Header:   D:/ECB2S/SRC/LOG/FWSETUP/JEDLOAD.CPP   1.7   17 Apr 1997 16:38:44   ZJRD  $
**
**    $Log:   D:/ECB2S/SRC/LOG/FWSETUP/JEDLOAD.CPP  $
** 
**    Rev 1.7   17 Apr 1997 16:38:44   ZJRD
** No change.
** 
**    Rev 1.6   16 Apr 1997 11:18:40   ZJRD
** No change.
** 
**    Rev 1.5   10 Apr 1997 15:59:36   ZJRD
** 2.09F
** 
**    Rev 1.3   03 Apr 1997 15:37:46   ZJRD
** No change.
** 
**    Rev 1.2   27 Mar 1997 15:22:22   ZJRD
** easy pack sld 2.09d
** 
**    Rev 1.1   19 Mar 1997 11:50:22   ZJRD
** No change.
** 
**    Rev 1.0   12 Mar 1997 15:02:28   ZJRD
** Initial revision.
** 
****************************************************************************/

/***************************************************************************
**
** File name :  JEDLOAD.CPP
**
** Author:      Chris Fang
** Description: implement file of JEDLOAD
**
** coding from: Feb 14, 1997
** Finished date:
**
**
**    Copyright (C) 1996 Microtek International, Inc.
**    All Rights Reserved
**
****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include "stdafx.h"
#include "resource.h"

#include "stdio.h"
#include "memory.h"
#include "ctype.h"
#include "flspro.h"
#include "flsmsg.h"
#include "flsinfo.h"
#include "abitype.h"
#include "abiextfn.h"

#define ispLSI1016_id           0x01
#define ispLSI1024_id           0x02
#define ispLSI1032_id           0x03
#define ispLSI1032E_id          0x0d
#define ispLSI1048_id           0x04
#define ispLSI1016_jedec_fuses  15360  /* number of fuses in JEDEC file     */
#define ispLSI1024_jedec_fuses  24480
#define ispLSI1032_jedec_fuses  34560U
#define ispLSI1032E_jedec_fuses  42880U
#define ispLSI1048_jedec_fuses  57600U

#define STX 0x02
#define ONE   1
#define JED_ERROR -3

enum FIELDTYPE { FT_START, FT_IGNORE, FT_QF, FT_UES, FT_LINK, FT_FILE_END };
struct UESDATA
	{
		BYTE type;
		BYTE ver;
		BYTE status;
		WORD year;
		BYTE month;
		BYTE day;
		char desc[40];
	};

unsigned char * isp_buffer;

/* function prototypes */
BOOL jedLoad(CString filename, BOOL bFromShell);
void ErrorHandler(CString& errmsg, BOOL bFromShell);
void ShowProcess(CProStatus* pps, int status);
//void halt(int msec);

FIELDTYPE isp_jed_fieldtype(FILE *jed_file,  unsigned int *data);
int isp_next_field(FILE *jed_file);
unsigned int isp_field_data(FILE *jed_file);
unsigned int isp_get_bits( FILE *jed_file, unsigned int first_bit);
int isp_setbit( unsigned int bit, BYTE value);

//1. check version: if file is old, pop dialog to let user confirm.
//2. pop process dialog.
//3. download success, pop status message box.
BOOL jedLoad(CString filename, BOOL bFromShell)
{
FILE *jed_file;
unsigned char * pData;
unsigned char * pUesData;
enum FIELDTYPE result;
int device, found_start, found_qf;
unsigned int bits_read;
unsigned int qf, data, nLength, nUesLength=0;
BOOL	bLoadUes=FALSE;
CString errMsg;
UESDATA	uesdata;
BYTE	oldver;
STATUS	retAbi;
const int cn_BufferLen=0x4000;

	jed_file = fopen(filename,"r");
	if (jed_file == NULL)
	{
		//ErrGetErrorText(ER_TST_OPEN_ERROR, errMsg);
		errMsg="Cannot open this file!";
		ErrorHandler(errMsg, bFromShell);
		return FALSE;
	}
	/* make sure it's a valid JEDEC file by locating an STX character */
	do
	{
		result = isp_jed_fieldtype( jed_file, &data);
		if( result == FT_START)
		{
			found_start = TRUE;
			break;
		}
	}while( !feof(jed_file) );

	if(!found_start)  /* end of file reached without finding STX char */
	{
		//ErrGetErrorText(ER_JED_STARTFLAG, errMsg);
		errMsg="File format error: cannot find start flag!";
		ErrorHandler(errMsg, bFromShell);
		fclose(jed_file);
		return(FALSE);
	}
	/* find the QF (quantity of fuses) field to determine device type */
	do
	{
		result = isp_jed_fieldtype( jed_file, &data);
		if( result == FT_QF )
		{
			qf = data;
			found_qf = TRUE;
			break;
		}
		if( result == FT_LINK ) /* Found fuse values BEFORE the device type */
		{                    /* could be identified.   */
			break;
		}
	}while( !feof(jed_file) );

	if(!found_qf)         /* could not find QF field */
	{
		//ErrGetErrorText(ER_JED_QFFLAG, errMsg);
		errMsg="File format error: cannot find QF flag!";
		ErrorHandler(errMsg, bFromShell);
		fclose(jed_file);
		return(FALSE);
	}
	/* set the device type */
	switch (qf)
	{
		case ispLSI1048_jedec_fuses:
			device = ispLSI1048_id;
			break;
		case ispLSI1032_jedec_fuses:
			device = ispLSI1032_id;
			break;
		case ispLSI1032E_jedec_fuses:
			device = ispLSI1032E_id;
			break;
		case ispLSI1024_jedec_fuses:
			device = ispLSI1024_id;
	 			break;
		case ispLSI1016_jedec_fuses:
			device = ispLSI1016_id;
			break;
		default:
			{
				//ErrGetErrorText(ER_JED_ERRQFFLAG, errMsg);
				errMsg="File format error: invalid QF flag!";
				ErrorHandler(errMsg, bFromShell);
				fclose(jed_file);
				return(FALSE);
			}
	}
	
	pUesData=new unsigned char[80];		//max is 40
	if(!pUesData)
	{
		//ErrGetErrorText(ER_OUT_OF_MEMORY, errMsg);
		errMsg="Out of memory!";
		ErrorHandler(errMsg, bFromShell);
		fclose(jed_file);
		return FALSE;
	}
	pData=new unsigned char[cn_BufferLen];
	if(!pData)
	{
		delete pUesData;
		//ErrGetErrorText(ER_OUT_OF_MEMORY, errMsg);
		errMsg="Out of memory!";
		ErrorHandler(errMsg, bFromShell);
		fclose(jed_file);
		return FALSE;
	}
	pData[0] = char(device);
	bits_read = 0;
	do
	{
		result = isp_jed_fieldtype( jed_file, &data);
		switch(result)
		{
			case  FT_LINK:
				isp_buffer=pData;
				nLength=isp_get_bits(jed_file, data); /* read until next field */
				ASSERT(nLength%8==0);
				nLength/=8;
				nLength++;			//the first byte
				break;
			case   FT_UES:
				isp_buffer=pUesData-1;
				bits_read = isp_get_bits(jed_file, 0);
				nUesLength=bits_read/8;
				bLoadUes=TRUE;
				break;
			default   :
				break; /* ignore other fields */
		}
	}while( !feof(jed_file) );
	//set ues data:
	if(bLoadUes)
 	{
		uesdata.type=pUesData[0];
		if(uesdata.type>=3)
		{
			errMsg="Error UES information in jed file, Cannot continue.";
			ErrorHandler(errMsg, bFromShell);
			delete pUesData;
			delete pData;
			fclose(jed_file);
			return FALSE;
		}
		uesdata.ver=pUesData[1];
		uesdata.status=pUesData[2];
		uesdata.year=pUesData[3]*100+pUesData[4];
		uesdata.month=pUesData[5];
		uesdata.day=pUesData[6];
		pUesData[7]=min(pUesData[7], 39);
		strncpy(uesdata.desc, (const char*)pUesData[8], pUesData[7]);
		uesdata.desc[pUesData[7]]=NULL;
	}
	else
	{
		errMsg="Not find UES information in jed file, Cannot continue.";
		ErrorHandler(errMsg, bFromShell);
		delete pUesData;
		delete pData;
		fclose(jed_file);
		return FALSE;
	}
	if(bLoadUes)
	{
		memcpy(pData+nLength, pUesData, nUesLength);
		nLength+=nUesLength;
	}
	if(cn_BufferLen<nLength)
	{
		errMsg="down load size too big!";
		ErrorHandler(errMsg, bFromShell);
		delete pUesData;
		delete pData;
		fclose(jed_file);
		return FALSE;
	}
	BYTE bLen;

	retAbi=AbiGetUesData(uesdata.type, bLen,pUesData);
	if(retAbi!=ICE_OK)
	{
		errMsg="Abi return error!";
		ErrorHandler(errMsg, bFromShell);
		delete pUesData;
		delete pData;
		fclose(jed_file);
		return FALSE;
	}
	//show info. dialog
	CInfoDlg *pInfoDlg;
	char *szFileName;

	pInfoDlg=new CInfoDlg;
	pInfoDlg->m_bJed=2;
	pInfoDlg->m_szFileName="Hardware UES info";
	pInfoDlg->m_uRecordNum=pUesData[2];
	pInfoDlg->m_uchMajor=pUesData[1];
	pInfoDlg->m_uchMinor=pUesData[0];
	pInfoDlg->m_lFileSize=nLength;
	pInfoDlg->m_uData=pUesData[6]+((pUesData[5]&0xf)<<5);
	pInfoDlg->m_uYear=(WORD(pUesData[3]*100+pUesData[4]));
	pInfoDlg->DoModal();       
	delete pInfoDlg;

	oldver=pUesData[1];
	if(uesdata.ver<=oldver)
	{
		CFlsMsg VerDlg;
		CFlsMsg *pVerDlg=&VerDlg;
		if(uesdata.ver<oldver)
			pVerDlg->m_strText="The version of hardware is high than the version of found jed file.\nDo you want to write?";
		else 
			pVerDlg->m_strText="The version of hardware is the same as the version of found jed file.\nDo you want to write?";
		if(IDCANCEL==pVerDlg->DoModal())
		{
			delete pUesData;
			delete pData;
			fclose(jed_file);
			return FALSE;
		}
    }
    WORD wAddr=0;
	CProStatus	ps;
    bLen=0;

	if(IDCANCEL==AfxMessageBox(
			"File Check is OK,\nDo You Want to Erase hardware!",MB_OKCANCEL))
	{
		delete pUesData;
		delete pData;
		fclose(jed_file);
		return FALSE;
	}
	ps.m_nRecordNum=int(nLength*1.1);
	ps.Create();
	while(wAddr<nLength)
	{
		ShowProcess(&ps, wAddr);
		bLen=BYTE(min(nLength-wAddr, 0x80));
		retAbi=AbiSendProgData(wAddr, bLen, pData+wAddr);
		//halt(bLen);
		if(retAbi!=ICE_OK)
		{
			//ErrGetErrorText(ER_ICE_OK+retAbi, errMsg);
			errMsg="Abi return error!";
			ErrorHandler(errMsg, bFromShell);
			delete pUesData;
			delete pData;
			fclose(jed_file);
			ps.DestroyWindow();
			return FALSE;
		}
		wAddr+=WORD(bLen);
	}
	retAbi=AbiProgram(uesdata.type, (BYTE)bLoadUes);
	if(retAbi!=ICE_OK)
	{
		//ErrGetErrorText(ER_ICE_OK+retAbi, errMsg);
		errMsg="Abi return error!";
		ErrorHandler(errMsg, bFromShell);
		delete pUesData;
		delete pData;
		fclose(jed_file);
		ps.DestroyWindow();
		return FALSE;	
	}
	else
		ShowProcess(&ps, int(nLength*1.1));
	ps.DestroyWindow();
	delete pUesData;
	delete pData;
	fclose(jed_file);

	//show info. dialog
	szFileName = new char[ filename.GetLength()+1 ];
	if ( !szFileName )
		return TRUE;
	strcpy( szFileName, filename.GetBuffer(filename.GetLength()) );
	pInfoDlg=new CInfoDlg;
	pInfoDlg->m_bJed=TRUE;
	pInfoDlg->m_szFileName=szFileName;
	pInfoDlg->m_uRecordNum=uesdata.status;
	pInfoDlg->m_uchMajor=uesdata.ver;
	pInfoDlg->m_uchMinor=uesdata.type;
	pInfoDlg->m_lFileSize=nLength;
	pInfoDlg->m_uData=uesdata.day+((uesdata.month&0xf)<<5);
	pInfoDlg->m_uYear=uesdata.year;
	pInfoDlg->DoModal();       
	delete szFileName;
	delete pInfoDlg;
	return TRUE;
}

void ErrorHandler(CString& errmsg, BOOL /*bFromShell*/)
{
	AfxMessageBox(errmsg);
	return;
}

void ShowProcess(CProStatus* pps, int status)
{
	pps->m_nDoneRecords=status;
	pps->InvalidateRect(&(pps->m_ProRect));
	pps->InvalidateRect(&(pps->m_IconRect));
	pps->UpdateWindow();
}

/**************************************************************************
   Function: isp_fieldtype();

   Purpose:
   To determine the JEDEC field type by looking at the first character(s)
   after the * delimiter. If the field is one that contains some data, this
   data is retrieved by calling isp_field_data(), and the data returned to
   the calling program or routine.

   Parameters:
    - jed_file, a file handle to the JEDEC file.

    - data, a pointer to  isp_STRUCT containing a pointer to the ispStream
      buffer.

   Returns:

    - the field type, as an emumerated value.

    Notes:

    - For the QP field, get the number of fuses, and return.

    - For the L and U fields, the fuse number is retrieved, and the
      file pointer is left as is, so the callling routine can get the fuses.

    - For the other fields, which are not used, the file pointer is
      advanced to the end of the field, so the next field can be read.


**************************************************************************/
enum FIELDTYPE isp_jed_fieldtype( FILE *jed_file, unsigned int *data)
{
char ch;

    while( (ch = char(getc( jed_file ))) != EOF)
    {

       if( isalpha(ch) || ch == STX)
       {
         switch (ch)
         {
           case STX:     isp_next_field(jed_file); /* go to end of field */
                         return(FT_START);

           case 'Q':     ch = char(getc( jed_file));
                         if( ch == 'P')
                         {
                           isp_next_field(jed_file);  /* ignore QP field */
                           return(FT_IGNORE);
                         }
                         else if( ch == 'F')
                         {
                           *data = isp_field_data(jed_file);
                           return(FT_QF);
                         }
                         else
                           return(FT_IGNORE);

           case 'U':     return(FT_UES);

           case 'L':     *data = isp_field_data(jed_file);
			 return(FT_LINK);

           default :     isp_next_field(jed_file);
                         return(FT_IGNORE);
         }
       }
     }
     return(FT_FILE_END);

} /* isp_jed_fieldtype() */

/*************************************************************************
   Function: isp_next_field()

   Pupose:
   To go to the end of the field, which means finding the next '*'.
   This just gets unneeded fields out of the way, and makes way for
   the next field to be read.

   Parameters:
    - jed_file, a file handle to the JEDEC file.

   Returns:
     - JED_ERROR, if the next * field delimiter can not be found.

    - ONE, if successful.


**************************************************************************/
int isp_next_field(FILE *jed_file)
{
char ch;

   while( (ch = char(getc(jed_file))) != EOF )
   {
     if( ch == '*')
        return ONE;
   }
   /* if * not found, it's an error */
   return(JED_ERROR);

} /* isp_next_field */


/**************************************************************************
    Function: isp_field_data()

   Pupose:
   Gets the data from most JEDEC file fields, such as the QF number or the
   Link number.

   Parameters:
    - jed_file, a file handle to the JEDEC file.

    Returns:
     - the data from the field, which is read as a string of ASCII numeric
      characters, and assembled into an integer value to be returned.

**************************************************************************/
unsigned int isp_field_data(FILE *jed_file)
{

char ch;
int found_digit = FALSE;
int data = 0;

   while( (ch = char(getc(jed_file))) != EOF )
   {
     if( found_digit && !isdigit(ch) )
        break; /* found end of multiple digit number */

     if( isdigit(ch) )

     {
       found_digit = TRUE;
       data = (data * 10) + (ch - '0');
     }
   }

   return(data);

} /* isp_field_data */

/**************************************************************************

   Function: isp_get_bits()

   Pupose:
   Gets the "fuse" data from a JEDEC Link field, and stores them in the
   the ispStream as a packed bit stream.

   Parameters:
    - jed_file, a file handle to the JEDEC file.

   Returns:
    - the data from the field, which is read as a string of ASCII numeric
      characters, and assembled into an integer value to be returned.


**************************************************************************/
unsigned int isp_get_bits( FILE *jed_file, unsigned int first_bit)
{

BYTE ch;
unsigned int bit;  /* JEDEC fuse number, as well as bit index */

  bit = first_bit;
  do
  {
    ch = BYTE(getc(jed_file));

    if( (ch == '0') || (ch == '1') )
    {
      isp_setbit( bit , BYTE(ch - '0') );
      bit++;
    }

    if(ch == '*') /* end of field */
      break;

   }while( !feof(jed_file) );

   return(bit - first_bit); /* number of bits read */

} /* isp_get_bits() */


/*************************************************************************
  function: isp_setbit()

  Purpose:
  Sets the specified bit in the isp stream buffer to value passed.


  Parameters:
   - bit, which is the offset in bits from the beginning of the _data_
     bits in the ispStream. When calling the routine, act as if the
     ID byte in the first byte of the ispStream is not there.

   - value, which binary value to set the bit to.

  Returns:
   - the value the bit was set to.

  Notes:
   It's hard to follow, but it works fine. Strongly recommend not modifying.


**************************************************************************/
int isp_setbit( unsigned int bit, BYTE value)
{

unsigned int byte_num, bit_num;

  byte_num = bit / 8;
  bit_num =  (8 - (bit % 8 )) - 1;

  if(!value)
     isp_buffer[byte_num+1] &= ~( (BYTE)(0x01<<bit_num) );
  else
     isp_buffer[byte_num+1] |=    (BYTE)(0x01<<bit_num);

  return(value);

} /* isp_setbit() */

/*
void halt(int msec)
{
DWORD time=GetTickCount()+msec;

	while(GetTickCount()<time)
		;
}
*/
