/**********************************************************************/
/*                                                                    */
/* File name: COM.c                                                   */
/*                                                                    */
/* Since:     2002/12/03                                              */
/*                                                                    */
/* Version:   1.02                                                    */
/*                                                                    */
/* Author:    MONTAGNE Xavier [XM] {link xavier.montagne@wanadoo.fr}  */
/*                                                                    */
/* Purpose: Offer high level interface for PIC programming operations:*/
/*          parsing or creat an HEX file, updating the PIC structures */
/*          after parsing, reading or programming the PIC,...         */
/*                                                                    */
/* Distribution: This file is part of PP18.                           */
/*               PP18 is free software; you can redistribute it       */
/*               and/or modify it under the terms of the GNU General  */
/*               Public License as published by the Free Software     */
/*               Foundation; either version 2, or (at your option)    */
/*               any later version.                                   */
/*                                                                    */
/*               PP18 is distributed in the hope that it will be      */
/*               useful, but WITHOUT ANY WARRANTY; without even the   */
/*               implied warranty of MERCHANTABILITY or FITNESS FOR A */
/*               PARTICULAR PURPOSE.  See the GNU General Public      */
/*               License for more details.                            */
/*                                                                    */
/*               You should have received a copy of the GNU General   */
/*               Public License along with PP18; see the file         */
/*               COPYING.txt. If not, write to the Free Software      */
/*               Foundation, 59 Temple Place - Suite 330,             */
/*               Boston, MA 02111-1307, USA.                          */
/*                                                                    */
/* History:                                                           */
/*      2002/12/03  [XM] Create this file                             */
/*                                                                    */
/**********************************************************************/

/***********************************************************************
 * INCLUDES
 **********************************************************************/
#include "driver.h"
#include "com.h"

/***********************************************************************
 * Avoid warning generate by this 'adaptation' for compilation
 **********************************************************************/
#pragma warning (disable: 4700)	


/***********************************************************************
 * DEFINES.
 **********************************************************************/

/******* Expected value of Record_type in HEX file ********************/
#define DATA_RECORD                      0x00

#define EXTENDED_SEGMENT_ADRESS_RECORD   0x02
#define START_SEGMENT_ADRESS_RECORD      0x03
#define EXTENDED_LINEAR_ADRESS_RECORD    0x04
#define START_LINEAR_ADRESS_RECORD       0x05

/******* For HEX file parser ******************************************/
#define END_OF_LINE						 0xDF
#define END_OF_FILE						 0xEF

/******* Defines dedicated to this PIC *********************************/ 
#define _DEFAULT_PATTERN_  0xFF
#define _MAX_PIC_SIZE      0x4000


/***********************************************************************
 * MACROS
 **********************************************************************/
#define REACH_END_OF_LINE(Record_Type,next,fd)	 do  \
												 {   \
											 		next = GetNextChar(fd);  \
													/* EOF without END_OF_FILE_RECORD */ \
													if (next == END_OF_FILE) \
														if (Record_Type == END_OF_FILE_RECORD)  \
														{  \
															break;  \
														}  \
														else  \
															/* EOF without END_OF_FILE_RECORD */ \
															return(0); \
												}while (next != END_OF_LINE);


/***********************************************************************
 * Global variables.
 **********************************************************************/
/******* Structures for data from/to PIC or file **********************/
extern HexFile_t HEX_from_file;
extern HexFile_t HEX_from_PIC;
extern unsigned short MemFile[_MAX_PIC_SIZE];
extern unsigned short MemPIC[_MAX_PIC_SIZE];
extern ConfigWord_t CFG_File;
extern ConfigWord_t CFG_PIC;

/******* Structure related to statistics if necessary *****************/ 
extern Statistic_t Stat;

/******* Checksum computation from file or PIC content ****************/
extern unsigned char Checksum;

/***********************************************************************
 * Parse an INTEL HEX file to fill a memory buffer.
 * Verify checksum for every line of the file. 
 *
 * @param  FILE *fd           IN  HEX filename to write in
 * @param  u_short *DataBytes IN  Reference to the memory buffer 
 * @param  u_int uiAddressMax IN  Number of addresses parsed
 * @return void               
 **********************************************************************/ 
int HexParserMemory(FILE *fd, unsigned short *Data_Bytes, unsigned int *uiAddressMax)
{
  unsigned char  Record_Marker;
  unsigned char  Record_Lenght;
  unsigned int   Adress;
  unsigned int   AdressExtended;
  unsigned char  Record_Type;
  unsigned int   the_size;
  
  unsigned short *Bookmark;
  unsigned short temp, temp2;
  unsigned char i, next, done, inc;

  Bookmark = Data_Bytes;

  AdressExtended = 0;
  Record_Marker = ':';
  Checksum = 0;
  the_size = 0;

  Record_Type = DATA_RECORD;
  while (Record_Type != END_OF_FILE_RECORD)
  {
  	Record_Marker = GetNextChar(fd);
  	while (Record_Marker == ';')
		REACH_END_OF_LINE(Record_Type,next,fd);

  	if (Record_Marker != ':')
  		return (0);
  		
  	Checksum = 0;
    done = 0;
    inc = 0;

  	Record_Lenght = GetNextByte(fd);
	Adress        = GetNextShortUnSwap(fd);
  	Record_Type   = GetNextByte(fd);

	Adress        = AdressExtended + Adress;

	/******* Program code or extended address only **********************/
	if ((Adress   < 0x200000) || (Record_Type == EXTENDED_LINEAR_ADRESS_RECORD))
	{
  		for (i = 0; i < (Record_Lenght / 2); i++)
  		{
	  		 if (Record_Type == DATA_RECORD)
			 {
                if ((Adress % 2) && (done == 0))
                {
				   Data_Bytes = Bookmark + (Adress / 2) + i;
                  *Data_Bytes &= (unsigned short)((GetNextByte(fd) << 8) + 0x00FF);
				  the_size++;
                  done = 1;
                  inc = 1;
                  if (Record_Lenght % 2)
                  {
                    Record_Lenght++;
                    inc = 0;
                  }
                }
                else
                {
                   Data_Bytes = Bookmark + (Adress / 2) + i;
  				  *Data_Bytes = GetNextShort(fd);
                  the_size++;
                }
			 }
			 if (Record_Type == EXTENDED_LINEAR_ADRESS_RECORD)
			 {
				temp = GetNextShort(fd);
				AdressExtended = (temp & 0xFF00) >> 8;
				AdressExtended = AdressExtended + ((temp & 0xFF) << 8);
				AdressExtended = AdressExtended << 16;
			 }
		}

        if ((i * 2) < (Record_Lenght + inc))
        {
             Data_Bytes = Bookmark + (Adress / 2) + i;
            *Data_Bytes = 0xFF00 + (unsigned short)(GetNextByte(fd));
        }

		Checksum = 0xFF - Checksum + 1;

		if (CompareChecksum(fd) == KO)
			return(KO);
	}
	else
	{
		/******* We don't need the content but just to read it **********/	
  		for (i = 0; i < (Record_Lenght / 2); i++)
	  		GetNextShort(fd); 
		CompareChecksum(fd);			
	}

	REACH_END_OF_LINE(Record_Type,next,fd);
  }

  *uiAddressMax = the_size;
  return (OK);
}

/***********************************************************************
 * Build a INTEL HEX file from memory buffer.
 * Compute checksum for every line of the file. 
 *
 * @param  FILE *fd           IN  HEX filename to write in
 * @param  u_short *DataBytes IN  Reference to the memory buffer 
 * @param  u_int uiAddressMax IN  Address Max = buffer_size x 2
 * @return void               
 **********************************************************************/  
void HexUnParserMemory(FILE *fd, unsigned short *DataBytes, unsigned int uiAddressMax)
{
  unsigned char Record_Marker;
  unsigned char Record_Lenght;
  unsigned short Address;
  unsigned char Record_Type;
  unsigned char i;

  Checksum = 0;

  /******* Set EXTENDED_LINEAR_ADRESS_RECORD to 0x200000 ****************/   
  SetNextChar (fd, ':');
  SetNextByte (fd, 0x02);
  SetNextShortUnSwap(fd, 0x00);
  SetNextByte (fd, EXTENDED_LINEAR_ADRESS_RECORD);
  SetNextShortUnSwap(fd, 0x0000);
  Checksum = 0xFF - Checksum + 1;
  SetNextByte(fd, Checksum);
  SetCR(fd);

  Record_Marker = ':';
  Record_Type   = DATA_RECORD;
  Address  = 0;

  /******* Fill the file with all the memory buffer *********************/   
  while (Address < uiAddressMax)
  {
  	Checksum = 0;
  	Record_Lenght = 0x10;

	SetNextChar (fd, Record_Marker);
	SetNextByte (fd, Record_Lenght);
	SetNextShortUnSwap(fd, Address);
  	SetNextByte (fd, Record_Type);
  	
  	for (i = 0; i < (Record_Lenght / 2); i++)
  	{
  		SetNextShort(fd, (unsigned short)(*DataBytes));
  		DataBytes++;
		Address = Address + 2;
	}
	
	Checksum = 0xFF - Checksum + 1;

	SetNextByte(fd, Checksum);
	SetCR(fd);
  }
}

/***********************************************************************
 * Parse a INTEL HEX file to extract the config values.
 *
 * @param  FILE *fd             IN  HEX filename to write in
 * @param  pConfigWord_t config IN  Config structure reference
 * @return int                      OK if sucessfull
 *                                  KO if checksum error occurs                
 **********************************************************************/  
int HexParserConfig(FILE *fd, pConfigWord_t config)
{
  unsigned char  Record_Marker;
  unsigned char  Record_Lenght;
  unsigned int   Address;
  unsigned int   AddressExtended;
  unsigned char  Record_Type;
  unsigned short Data_Bytes;
  
  unsigned char i, next;

  AddressExtended = 0;
  Record_Marker = ':';
  Checksum = 0;

  Record_Type = DATA_RECORD;
  while (Record_Type != END_OF_FILE_RECORD)
  {
  	Record_Marker = GetNextChar(fd);

  	while (Record_Marker == ';')
		REACH_END_OF_LINE(Record_Type,next,fd);

  	if (Record_Marker != ':')
  		return (0);  	
	
  	Checksum = 0;

  	Record_Lenght = GetNextByte(fd);
	Address       = GetNextShortUnSwap(fd);
  	Record_Type   = GetNextByte(fd);

	Address       = AddressExtended + Address;
	
	/******* Program code or extended address only **********************/ 
	if ((Address  >= 0x300000) || (Record_Type == EXTENDED_LINEAR_ADRESS_RECORD))
	{
	  	for (i = 0; i < (Record_Lenght / 2); i++)
  		{
			Data_Bytes = GetNextShort(fd);

			if (Record_Type == DATA_RECORD)
				switch(Address)
				{
				case 0x300000:
					config->szFosc          = (Data_Bytes & 0x0700) >> 8;
					config->szOscsen        = (Data_Bytes & 0x2000) ? 0 : 1;
					break;
				case 0x300002:
					config->szPwrten        = (Data_Bytes & 0x0001) ? 0: 1;
					config->szBoren         = (Data_Bytes & 0x0002) ? 1: 0;
					config->szBorv          = (Data_Bytes & 0x000C) >> 2;
					config->szWdten         = (Data_Bytes & 0x0100) >> 8;
					config->szWdtps         = (Data_Bytes & 0x0E00) >> 9;
					break;
				case 0x300004:
					config->szCcp2mx        = (Data_Bytes & 0x0100) >> 8;
					break;
				case 0x300006:
					config->szStvren        =  Data_Bytes & 0x0001;
                    config->szLVP           = (Data_Bytes & 0x0004) ? 1 : 0;
                    config->szDebug         = (Data_Bytes & 0x0080) ? 0 : 1;
					break;
				case 0x300008:
					config->szCodeProtected  = (Data_Bytes & 0xC000) >> 8;
                    config->szCodeProtected += (Data_Bytes & 0x000F);
					break;
				case 0x30000A:
					config->szWriteProtected  = (Data_Bytes & 0xE000) >> 8;
                    config->szWriteProtected += (Data_Bytes & 0x000F);
					break;
				case 0x30000C:
					config->szTableReadProtected  = (Data_Bytes & 0x4000) >> 8;
                    config->szTableReadProtected += (Data_Bytes & 0x000F);
					break;
				}

			Address += 2;
		}

		if (Record_Type == EXTENDED_LINEAR_ADRESS_RECORD)
		{
			AddressExtended = ((Data_Bytes) & 0xFF00) >> 8;
			AddressExtended = AddressExtended + (((Data_Bytes) & 0xFF) << 8);
			AddressExtended = AddressExtended << 16;
		}

		Checksum = 0xFF - Checksum + 1;

		if (CompareChecksum(fd) == KO)
			return(KO);
	}

	REACH_END_OF_LINE(Record_Type,next,fd);
  }

  return(OK);
}

/***********************************************************************
 * Build a INTEL HEX file from config structure.
 * Compute checksum for only one line. 
 *
 * @param  FILE *fd           IN  HEX filename to write in
 * @param  pConfigWord_t cfg  IN  Reference to the config structure
 * @return void               
 **********************************************************************/  
void HexUnParserConfig(FILE *fd, pConfigWord_t cfg)
{
  unsigned char  Record_Marker;
  unsigned char  Record_Lenght;
  unsigned short Address;
  unsigned char  Record_Type;
  unsigned short word;

  Checksum = 0;

  /******* Set EXTENDED_LINEAR_ADRESS_RECORD to 0x300000 ****************/ 
  SetNextChar (fd, ':');
  SetNextByte (fd, 0x02);
  SetNextShortUnSwap(fd, 0x00);
  SetNextByte (fd, EXTENDED_LINEAR_ADRESS_RECORD);
  SetNextShortUnSwap(fd, 0x0030);
  Checksum = 0xFF - Checksum + 1;
  SetNextByte(fd, Checksum);
  SetCR(fd);

  Record_Marker = ':';
  Record_Type   = DATA_RECORD;
  Checksum = 0;
  Address  = 0;

  Record_Lenght = 0x0E;

  SetNextChar (fd, Record_Marker);
  SetNextByte (fd, Record_Lenght);
  SetNextShortUnSwap(fd, Address);
  SetNextByte (fd, Record_Type);
  
  word = ((((cfg->szOscsen ? 0 : 1) << 13) + (cfg->szFosc << 8)) & (0x2700));
		 ((cfg->szCodeProtected) & (0x00FF));
  SetNextShort(fd, word);
	
  word = (((cfg->szWdtps << 9) + (cfg->szWdten << 8)) & (0x0F00)) + \
	     (((cfg->szBorv << 2)  + (cfg->szBoren << 1)) & (0x000E))+  \
		 ( (cfg->szPwrten) ? 0 : 1);
  SetNextShort(fd, word);

  word = (cfg->szCcp2mx << 8) & (0x0100);
  SetNextShort(fd, word);

  word = ((cfg->szStvren) & (0x0001)) + ((cfg->szLVP << 2) & (0x0004)) + \
         (((cfg->szDebug ? 0 : 1) << 7) & (0x0080));
  SetNextShort(fd, word);

  word = ((cfg->szCodeProtected) & (0x000F)) + (((cfg->szCodeProtected) & (0x00C0)) << 8);
  SetNextShort(fd, word);

  word = ((cfg->szWriteProtected) & (0x000F)) + (((cfg->szWriteProtected) & (0x00E0)) << 8);
  SetNextShort(fd, word);

  word = ((cfg->szTableReadProtected) & (0x000F)) + (((cfg->szTableReadProtected) & (0x0040)) << 8);
  SetNextShort(fd, word);

  Checksum = 0xFF - Checksum + 1;
  SetNextByte(fd, Checksum);
  SetCR(fd);
}

/***********************************************************************
 * Build a INTEL HEX file from ID structure.
 * Compute checksum for only one line. 
 *
 * @param  FILE *fd            IN  HEX filename to write in
 * @param  pHexFile_t p_hfFile IN  HEX structure reference
 * @return void               
 **********************************************************************/   
void HexUnParserID(FILE *fd, pHexFile_t p_hfFile)
{
  unsigned char  Record_Marker;
  unsigned char  Record_Lenght;
  unsigned short Address;
  unsigned char  Record_Type;
  unsigned short word;
  
  unsigned char i;

  Checksum = 0;

  /******* Set EXTENDED_LINEAR_ADRESS_RECORD to 0x200000 ****************/
  SetNextChar (fd, ':');
  SetNextByte (fd, 0x02);
  SetNextShortUnSwap(fd, 0x00);
  SetNextByte (fd, EXTENDED_LINEAR_ADRESS_RECORD);
  SetNextShortUnSwap(fd, 0x0020);
  Checksum = 0xFF - Checksum + 1;
  SetNextByte(fd, Checksum);
  SetCR(fd);

  Record_Marker = ':';
  Record_Type   = DATA_RECORD;
  Checksum = 0;
  Address  = 0;

  Record_Lenght = 0x08;

  SetNextChar (fd, Record_Marker);
  SetNextByte (fd, Record_Lenght);
  SetNextShortUnSwap(fd, Address);
  SetNextByte (fd, Record_Type);
	
  for (i = 0; i < 4; i++)
  {
	word = (p_hfFile->szIdValue[i*2+1] << 8) + p_hfFile->szIdValue[i*2];
	SetNextShort(fd, word);
  }

  Checksum = 0xFF - Checksum + 1;
  SetNextByte(fd, Checksum);
  SetCR(fd);
}

/***********************************************************************
 * Parse a INTEL HEX file to extract the ID values.
 *
 * @param  FILE *fd            IN  HEX filename to write in
 * @param  pHexFile_t p_hfFile IN  HEX structure reference
 * @return int                     OK if sucessfull
 *                                 KO if checksum error occurs                
 **********************************************************************/  
int HexParserID(FILE *fd, pHexFile_t p_hfFile)
{
  unsigned char  Record_Marker;
  unsigned char  Record_Lenght;
  unsigned int   Address;
  unsigned int   AddressExtended;
  unsigned char  Record_Type;
  unsigned short Data_Bytes;
  
  unsigned char i, next;

  AddressExtended = 0;
  Record_Marker = ':';
  Checksum = 0;

  Record_Type = DATA_RECORD;
  while (Record_Type != END_OF_FILE_RECORD)
  {
  	Record_Marker = GetNextChar(fd);

  	while (Record_Marker == ';')
		REACH_END_OF_LINE(Record_Type,next,fd);

  	if (Record_Marker != ':')
  		return (0);  	
	
  	Checksum = 0;

  	Record_Lenght = GetNextByte(fd);
	Address       = GetNextShortUnSwap(fd);
  	Record_Type   = GetNextByte(fd);

	Address       = AddressExtended + Address;
	
	/******* Program code or extended address only **********************/ 	
	if ((Address  >= 0x200000) || (Record_Type == EXTENDED_LINEAR_ADRESS_RECORD))
	{
	  	for (i = 0; i < (Record_Lenght / 2); i++)
  		{
			Data_Bytes = GetNextShort(fd);

			if (Record_Type == DATA_RECORD)
				if ((Address >= 0x200000) && (Address <= 0x200008))
				{
					p_hfFile->szIdValue[Address - 0x200000]     =  Data_Bytes & 0x00FF;
					p_hfFile->szIdValue[Address - 0x200000 + 1] = (Data_Bytes & 0xFF00) >> 8;
				}

			Address += 2;
		}

		if (Record_Type == EXTENDED_LINEAR_ADRESS_RECORD)
		{
			AddressExtended = ((Data_Bytes) & 0xFF00) >> 8;
			AddressExtended = AddressExtended + (((Data_Bytes) & 0xFF) << 8);
			AddressExtended = AddressExtended << 16;
		}

		Checksum = 0xFF - Checksum + 1;

		if (CompareChecksum(fd) == KO)
			return(KO);
	}

	REACH_END_OF_LINE(Record_Type,next,fd);
  }

  return(OK);
}

/***********************************************************************
 * Switch on an IO pin of the parallel port.
 *
 * @param  PIN_LABEL name      IN  Signal name
 * @return void
 **********************************************************************/
void TestIO_ON(PIN_LABEL name)
{
  SetBit(name);
}

/***********************************************************************
 * Switch off an IO pin of the parallel port.
 *
 * @param  PIN_LABEL name      IN  Signal name
 * @return void
 **********************************************************************/
void TestIO_OFF(PIN_LABEL name)
{
  ClearBit(name);
}

/***********************************************************************
 * Assign an IO pin of the parallel port as an ICSP IO.
 *
 * @param  PIN_LABEL name      IN  Signal name
 * @param  u_char ucMask       IN  Signal mask 
 * @param  u_char ucStatus     IN  Signal status 
 * @return void
 **********************************************************************/  
void Settings(PIN_LABEL name, unsigned char mask, unsigned char status)
{
  ConfigBit(name, mask, status);
}

/***********************************************************************
 * Get the mask and status of a signal.
 *
 * @param  PIN_LABEL name      IN  Signal name
 * @param  u_char *ucMask      IN  Signal mask 
 * @param  u_char *ucStatus    IN  Signal status 
 * @return void  
 **********************************************************************/ 
void ReadSettings(PIN_LABEL name, unsigned char *ucMask, unsigned char *ucStatus)
{
  *ucMask   = GetMask(name);
  *ucStatus = GetStatus(name);
}

/***********************************************************************
 * Read Data From Pic signal from parallel port.
 *
 * @param  u_char *p_puszValue IN  Reference to the checksum computed
 * @return void  
 **********************************************************************/  
void ReadDataFromPic(unsigned char *pucValue)
{
	if(!pucValue)
		return;

	*pucValue = (unsigned char)(ReadBit(PL_DATA_FROM_PIC));
}

/***********************************************************************
 * Extract the checksum info from every line of an INTEL HEX file.
 * Compare it with the value computed by the HEX parser.
 *
 * @param  FILE *fd            IN  file descriptor
 * @return unsigned char           OK if sucessfull
 *                                 KO if checksum error occurs
 **********************************************************************/
unsigned char CompareChecksum(FILE *fd)
{
  if (((GetNextChar(fd) << 4) + GetNextChar(fd)) != Checksum)
	return (KO);
  else
  	return (OK);
}

/***********************************************************************
 * Read the next short from an INTEL HEX file line.
 * Swap the low and hight bytes of the short. 
 *
 * @param  FILE *fd            IN  file descriptor
 * @return u_short value           Data read from the file 
 **********************************************************************/ 
unsigned short GetNextShort(FILE *fd)
{
  unsigned short value;
  value = GetNextByte(fd) + (GetNextByte(fd) << 8);
  
  return (value);
}

/***********************************************************************
 * Read the next short from an INTEL HEX file line.
 * Do not swap the low and hight bytes of the short. 
 *
 * @param  FILE *fd            IN  file descriptor
 * @return u_short value           Data read from the file 
 **********************************************************************/
unsigned short GetNextShortUnSwap(FILE *fd)
{
  unsigned short value;
  value = (GetNextByte(fd) << 8) + GetNextByte(fd);
  
  return (value);
}

/***********************************************************************
 * Write the next short into an INTEL HEX file.
 * Swap the low and hight bytes of the short. 
 *
 * @param  FILE *fd            IN  file descriptor
 * @param  u_short value       IN  Data to write into the file  
 * @return void 
 **********************************************************************/ 
void SetNextShort(FILE *fd, unsigned short value)
{
  SetNextByte(fd,  (unsigned char)(value & 0xFF));
  SetNextByte(fd, (unsigned char)((value >> 8) & 0xFF));
  return;
}

/***********************************************************************
 * Write the next short into an INTEL HEX file.
 * Do not swap the low and hight bytes of the short.
 *
 * @param  FILE *fd            IN  file descriptor
 * @param  u_short value       IN  Data to write into the file  
 * @return void 
 **********************************************************************/  
void SetNextShortUnSwap(FILE *fd, unsigned short value)
{
  SetNextByte(fd, (unsigned char)((value >> 8) & 0xFF));
  SetNextByte(fd,  (unsigned char)(value & 0xFF));
  return;
}

/***********************************************************************
 * Read the next char from an INTEL HEX file line.
 *
 * @param  FILE *fd            IN  file descriptor
 * @return u_char value            Data read from the file 
 **********************************************************************/   
unsigned char GetNextByte(FILE *fd)
{
  unsigned char value;
  value = (GetNextChar(fd) << 4) + GetNextChar(fd);
  Checksum += value;
  return (value);
}

/***********************************************************************
 * Write the next char into an INTEL HEX file.
 *
 * @param  FILE *fd            IN  file descriptor
 * @param  u_char value        IN  Data to write into the file  
 * @return void 
 **********************************************************************/  
void SetNextByte(FILE *fd, unsigned char value)
{
  SetNextChar(fd, (unsigned char)((value >> 4) & 0x0F));
  SetNextChar(fd, (unsigned char)(value & 0x0F));
  Checksum += value;  
  return;
}

/***********************************************************************
 * Extract 8 bits data from a file.
 * Convert data from dec to hex.
 *
 * @param  FILE *fd            IN  file descriptor
 * @return u_char value            Data read from the file 
 **********************************************************************/   
unsigned char GetNextChar(FILE *fd)
{
  unsigned char value;
  
  value = fgetc(fd);
  if ((value >= '0') && (value <= '9'))
	return (value - '0');
  if ((value >= 'a') && (value <= 'f'))
  	return (value - 'a' + 10);
  if ((value >= 'A') && (value <= 'F')) 
  	return (value - 'A' + 10);

  if (value == '\n')
	value = END_OF_LINE;

  if (feof(fd))
	value = END_OF_FILE;

  return (value);
}

/***********************************************************************
 * Write 8 bits data into a file.
 * Convert data from dec to hex.
 *
 * @param  FILE *fd            IN  file descriptor
 * @param  u_char value        IN  Data to write into the file 
 * @return void 
 **********************************************************************/  
void SetNextChar(FILE *fd, unsigned char value)
{
  if (value <= 9)
	value = (value + '0');
  if ((value >= 0x0a) && (value <= 0x0f))
  	value = (value + 'A' - 10);

  putc(value, fd);
  return;
}

/***********************************************************************
 * Write a CR to the end of a file.
 *
 * @param  FILE *fd            IN  file descriptor
 * @return void                  
 **********************************************************************/  
void SetCR(FILE *fd)
{
  putc('\n', fd);
  return;
}

/***********************************************************************
 * Compute a checksum of all the program memory.
 *
 * @param  pHexFile_t p_hfFile IN  HEX structure reference
 * @return unsigned short          Checksum computed (16 bits long)
 **********************************************************************/  
unsigned short ComputeMemChecksum(pHexFile_t p_hfFile)
{
  unsigned int i;
  unsigned short temp1, temp2;
  unsigned short result;
  unsigned short *pusMem;
  pusMem = p_hfFile->pusMemory;

  result = 0;
  for (i = 0; i < p_hfFile->uiMemorySize; i++)
  {
	temp1  = *(pusMem) & 0x00FF;
    temp2  = *(pusMem++) & 0xFF00;
	result += (temp1 + (temp2 >> 8));
  }
  
  return(result);
}

/***********************************************************************
 * Compute a checksum of all the config memory.
 *
 * @param  pHexFile_t p_hfFile IN  HEX structure reference
 * @return unsigned short          Checksum computed (16 bits long)
 **********************************************************************/  
unsigned short ComputeConfigChecksum(pHexFile_t p_hfFile)
{
  unsigned short config1L, config2L, config3L, config4L, config5L, config6L, config7L;
  unsigned short config1H, config2H, config3H, config4H, config5H, config6H, config7H;
  unsigned short result;

  config1L = 0x00;

  config1H = (((p_hfFile->pConfig->szOscsen ? 0 : 1) << 5) + \
             p_hfFile->pConfig->szFosc) & 0x27;

  config2L = ((p_hfFile->pConfig->szBorv << 2) + (p_hfFile->pConfig->szBoren << 1) +  \
		     ( (p_hfFile->pConfig->szPwrten) ? 0 : 1)) & 0x0F;

  config2H = ((p_hfFile->pConfig->szWdtps << 1) + p_hfFile->pConfig->szWdten) & 0x0F;

  config3L = 0x00;

  config3H =  (p_hfFile->pConfig->szCcp2mx) & 0x01;

  config4L =  ((p_hfFile->pConfig->szStvren) & 0x01) + \
              ((p_hfFile->pConfig->szLVP)    <<  2 ) + \
              ((p_hfFile->pConfig->szDebug ? 0 : 1)  <<  7 );

  config4H = 0x00;

  config5L = p_hfFile->pConfig->szCodeProtected & 0x0F;

  config5H = p_hfFile->pConfig->szCodeProtected & 0xC0;

  config6L = p_hfFile->pConfig->szWriteProtected & 0x0F;

  config6H = p_hfFile->pConfig->szWriteProtected & 0xE0;

  config7L = p_hfFile->pConfig->szTableReadProtected & 0x0F;

  config7H = p_hfFile->pConfig->szTableReadProtected & 0x40;

  result = config1L + config1H + config2L + config2H + config3L + config3H + \
		   config4L + config4H + config5L + config5H + config6L + config6H + \
		   config7L + config7H;

  return(result);
}

/***********************************************************************
 * Compute a checksum of 4 lower bits of the ID location.
 *
 * @param  pHexFile_t p_hfFile IN  HEX structure reference
 * @return unsigned short          Checksum computed (16 bits long)
 **********************************************************************/ 
unsigned short ComputeIDChecksum(pHexFile_t p_hfFile)
{
  unsigned int i;
  unsigned char temp;
  unsigned short result;

  result = 0;
  for (i = 0; i < 8; i++)
  {
	temp    = p_hfFile->szIdValue[i] & 0x0F;
	result += temp;
  }
  
  return(result);
}

#pragma warning(default: 4700)


