// HEX2BIN.C

// Convert Binary-file to INTEL-HEX-FORMAT

#include <dos.h>
#include <alloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "e:\l\mylib\include\mytypes.h"

INT error=0;

VOID exit_fn(VOID)
{
  if (error)
  {
    printf("\nConvert BIN -> HEX-Format\n"
           "usage: BIN2HEX name oooo\n"
           "       name....source <name>.BIN\n"
           "       oooo....offset in hex-notation\n"
           "       creates <name>.HEX starting at <oooo>\n"
          );
  }
}

CHAR HEXDIGITS[] = "0123456789ABCDEF";

INT ishex(UCHAR hex)
{
  return strchr(HEXDIGITS,toupper(hex))!=0;
}

UCHAR hex2bin(UCHAR hi, UCHAR lo)
{

  return (strchr(HEXDIGITS,toupper(hi)) - HEXDIGITS) * 16 +
         (strchr(HEXDIGITS,toupper(lo)) - HEXDIGITS);
}

UINT bin2hex(UCHAR bin)
{
  return HEXDIGITS[bin >> 4]*256+HEXDIGITS[bin & 0x0f];
}

void update_HEX(CHAR byte, UINT *chk, CHAR **b)
{
  UINT hexbyte;
  *chk+=byte;
  hexbyte=bin2hex(byte);
  *(*b)++=hexbyte>>8;
  *(*b)++=hexbyte&0x00ff;
}

/* process_HEX
 *************
 * l HEX-line
 * n number of bytes
 *   n=0: write endrecord
 * b points to first byte
 */

INT process_HEX(CHAR *l, UINT a, INT n, UCHAR *b)
{
  *l++=':';  /* identifier, start of line */

  UINT chksum=0;

  if (n==0) /* End */
  {
    /* len */
    *l++='0'; *l++='0';
    /* address */
    *l++='0'; *l++='0'; *l++='0'; *l++='0';
    /* type */
    *l++='0'; *l++='1';
    /* checksum */
    *l++='F'; *l++='F';
  }
  else /* Data */
  {
    if (n>16)
    {
      return 1;
    }

    /* length */
    update_HEX(n,&chksum,&l);

    /* address */
    update_HEX(a>>8,&chksum,&l);
    update_HEX(a&0x00ff,&chksum,&l);

    /* type */
    *l++='0';
    *l++='0';

    /* data */
    for (INT i=0; i<n; i++)
    {
      update_HEX(*b++,&chksum,&l);
    }

    /* chksum */
    update_HEX((0-chksum)%256,&chksum,&l);
  }
  *l=0; /* terminate string */
  return 0;
}

VOID main(INT argc, CHAR *argv[])
{
  UINT address;

  atexit(exit_fn);

  if (argc!=3)
  {
    error=1;
    exit(EXIT_FAILURE);
  }

  if (strlen(argv[2])!=4)
  {
    error=1;
    exit(EXIT_FAILURE);
  }

  for (INT i=0; i<4; i++)
  {
    if (!ishex(argv[2][i]))
    {
      printf("Address requires hex-notation\n");
      error=1;
      exit(EXIT_FAILURE);
    }
  }

  address = hex2bin(argv[2][0],argv[2][1])*256 +
            hex2bin(argv[2][2],argv[2][3]);

  // Open file to be created
  // ***********************************************
  FILE *fdst=NULL; // source-file
  CHAR dateiHEX[128];
  strcpy(dateiHEX, argv[1]);
  strcat(dateiHEX, ".HEX");
  fdst = fopen(dateiHEX,"wt");
  if (fdst==NULL)
  {
    printf("File %s does not exist\n",dateiHEX);
    fclose (fdst);
    exit(EXIT_FAILURE);
  }

  // Open BIN-File
  // ***********************************************
  FILE *fbin=NULL; // binary-file
  CHAR dateiBIN[128];
  strcpy(dateiBIN, argv[1]);
  strcat(dateiBIN, ".BIN");
  printf("Opening binary file %s\n",dateiBIN);
  fbin = fopen(dateiBIN,"rb");
  if (fbin==NULL)
  {
    printf("File %s cannot be opened\n",dateiBIN);
    fclose (fbin);
    exit(EXIT_FAILURE);
  }

  printf("writing HEX-File\n");
  for (;;)
  {
    CHAR line[80];
    UCHAR buffer[16];
    UCHAR len;

    len=fread(buffer,1,16,fbin);

    if (len)
    {
      process_HEX(line,address,len,buffer);
      address = address + len;
      fprintf(fdst,"%s\n",line);
    }
    else /* terminating record */
    {
      process_HEX(line,address,0,buffer);
      fprintf(fdst,"%s\n",line);
      printf("closing\n");
      break;
    }
  }

  fclose(fbin);
  fclose(fdst);
  exit(EXIT_SUCCESS);
}

