/* **********************************************************************
 * *                                                                    *
 * *           Utility to Work With Intel Hex "ROM" Records             *
 * *                                                                    *
 * **********************************************************************
 * File: utils/dsp/ihexutil.C
 *
 *                    COPYRIGHT (c) 2000, 2003  BY
 *         SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 *
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 */
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INCLUDE_STDIO_PROTOTYPES 1
#include "sigtypes.h"
#include "dsp_lib.h"

static void usage( void ) ;

/* ==================================================
 * Test utility (which actually does some useful work) for the Intel HEX
 * library routines in the DSP driver.
 */
int main( int argc_a, char **argv_a )
{
  UINT4 ii, iline ; FILE *fdes ; UINT1 lContinue ;
  char sRecord[ IHEX_MAXRECL + 10 ] ;

  UINT4 iRomCsumAddr, iRomCsum, iDecOffset ;
  UINT4 iRomSize=0x20000, iRomBlankValue=0xFF ;
  UINT1 lMakeRomCsum=FALSE ; char *sFileName=NULL ;

  /* Parse command line options
   */
  for( ii = 1 ; ii < (UINT4)argc_a ; ii++ ) {
    char *sarg = argv_a[ii] ;
    int ilen = strlen( sarg ) - 1 ;

    if( (sarg[0] == '-') && (ilen>0) ) {

      if( 0 == strncmp( &sarg[1], "csaddr", ilen ) ) {
	if( (++ii < (UINT4)argc_a) &&
	    (sscanf( argv_a[ii], "%x", &iRomCsumAddr ) == 1) ) {
	  lMakeRomCsum = TRUE ; continue ;
	} else {
	  fprintf( stderr, "Missing address for '-csaddr N'\n" ) ; exit(1) ;
	}
      }
      if( 0 == strncmp( &sarg[1], "romsize", ilen ) ) {
	if( (++ii < (UINT4)argc_a) &&
	    (sscanf( argv_a[ii], "%x", &iRomSize ) == 1) ) {
	  continue ;
	} else {
	  fprintf( stderr, "Missing size for '-romsize N'\n" ) ; exit(1) ;
	}
      }
      if( 0 == strncmp( &sarg[1], "blank", ilen ) ) {
	if( (++ii < (UINT4)argc_a) &&
	    (sscanf( argv_a[ii], "%x", &iRomBlankValue ) == 1) ) {
	  iRomBlankValue &= 0xFF ; continue ;
	} else {
	  fprintf( stderr, "Missing value for '-blank N'\n" ) ; exit(1) ;
	}
      }

      fprintf( stderr, "Unknown command line option '%s'\n", sarg ) ;
      usage() ; exit(1) ;

    } else {
      if( ii == 1 ) {
	sFileName = argv_a[1] ;
      } else {
	fprintf( stderr, "Unknown command line argument '%s'\n", sarg ) ;
	usage() ; exit(1) ;
      }
    }
  }

  /* Open the HEX file, or use the standard input if no file name was
   * given.
   */
  if( sFileName != NULL ) {
    if( NULL == (fdes = fopen( sFileName, "r" )) ) {
      fprintf( stderr, "Could not open '%s'\n", sFileName ) ; exit(1) ;
    }
  } else {
    fdes = stdin ;
  }

  /* Initialize according to what we've been asked to do.
   */
  if( lMakeRomCsum ) {
    iRomCsum = 0 ;
    for( ii=0 ; ii < iRomSize ; ii++ ) {
      iRomCsum += intelHexCS( ii, iRomBlankValue ) ;
    }
  }

  /* Process the input file.
   */
  iDecOffset = 0 ; lContinue = TRUE ; iline = 1 ;

  while( lContinue &&
	 (NULL != fgets( sRecord, sizeof(sRecord), fdes )) ) {

    UINT1 iData[IHEX_MAXDATA] ; SINT4 iLength ; UINT4 iAddress ;

    if( sRecord[0] != ':' ) continue ;
    switch( intelHexDecode( sRecord, iData, &iLength,
			    &iAddress, &iDecOffset ) ) {
    case IHEX_EOF:		/* Normal EOF */
      lContinue = FALSE ;
      break ;
    case IHEX_BADREC:		/* Junk in record */
      fprintf( stderr, "Garbled HEX record at line %d.\n", iline ) ; exit(1) ;
      break ;
    case IHEX_CHECKSUM:		/* Checksum error in record */
      fprintf( stderr, "HEX record checksum error at line %d.\n", iline ) ; exit(1) ;
      break ;

    case IHEX_NORMAL:		/* ========== Process Another Record ========== */
      if( lMakeRomCsum ) {
	for( ii=0 ; ii < (UINT4)iLength ; ii++ ) {
	  UINT4 iaddr = (iAddress + ii) ;
	  if( iaddr < iRomSize ) {
	    iRomCsum -= intelHexCS( iaddr, iRomBlankValue ) ;
	    iRomCsum += intelHexCS( iaddr, iData[ii]      ) ;
	  }
	}
      }
      break ;
    }
    iline++ ;
  }

  /* Finish up, according to what we've been asked to do.
   */
  if( lMakeRomCsum ) {
    UINT1 iData[4] ; UINT4 iEncOffset = (UINT4)-1 ;

    iData[0] = (UINT1)((iRomCsum >>  0) & 0xFF) ;
    iData[1] = (UINT1)((iRomCsum >>  8) & 0xFF) ;
    iData[2] = (UINT1)((iRomCsum >> 16) & 0xFF) ;
    iData[3] = (UINT1)((iRomCsum >> 24) & 0xFF) ;

    intelHexEncode( iData, 4, iRomCsumAddr, &iEncOffset, stdout ) ;
  }

  return(0) ;
}

/* ==================================================
 * Print command line options
 */
static void usage( void )
{
  fprintf( stderr, "Command line options:\n" ) ;
  fprintf( stderr, "   -csaddr <HEX> : Specify address for ROM checksum\n" ) ;
  fprintf( stderr, "  -romsize <HEX> : Specify size of ROM\n" ) ;
  fprintf( stderr, "    -blank <HEX> : Specify blank state of ROM\n" ) ;
}
