/*
Copyright (C) 2002 Pedro Zorzenon Neto <pzn@vztech.com.br>

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Do not forget to visit Free Software Foundation site: http://fsf.org

$Id: eep24c.c,v 1.3 2003/07/05 18:23:22 pzn Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "common.h"
#include "intelhex.h"
#include "eeprom.h"
#include "conf.h"

#define EEP_VERSION "0.1.2"

#define EEP_READ 1
#define EEP_WRITE 2
#define EEP_READWRITE 3
#define EEP_FILL 4

int mem_to_ihex (char * filename, memory_t * mem);
int ihex_to_mem (char * filename, memory_t * mem);

int mem_to_ihex (char * filename, memory_t * mem) {
  inteldata ihex;
  int reclen=0x10;
  unsigned int size, i, j;

  size=mem->size;

  assert( (size%reclen) == 0 );

  intelhex_fileopen ( &ihex, filename, 0);
  ihex.reclen=reclen;
  for (i=0; i<size; i+=reclen) {
    ihex.offset=i;
    for (j=0; j<reclen; j++) {
      ihex.recdata[j]=(unsigned char) memory_read(mem,i+j);
    }
    intelhex_writeline (&ihex);
  }
  intelhex_writeeof (&ihex);
  intelhex_fileclose (&ihex);
  return 1;
}

int ihex_to_mem (char * filename, memory_t * mem) {
  inteldata ihex;
  int i;
  intelhex_fileopen ( &ihex, filename, 1);
  while ( intelhex_readline (&ihex)==1 ) {
    for (i=0; i<ihex.reclen; i++) {
      memory_write(mem, ihex.offset+i, (int) ihex.recdata[i]);
    }
  }
  intelhex_fileclose (&ihex);
  return 1;
}

int main (int argc, char *argv[]) {

  eeprom_t *eep=NULL;
  unsigned long int par[5];
  int mode=0;
  memory_t * mem;
  unsigned int microdelay_factor = 1;

  if ( argc == 2 ) {
    if ( (strcmp(argv[1],"--help")==0) ||
	 (strcmp(argv[1],"-h")==0) ||
	 (strcmp(argv[1],"-?")==0) ||
	 (strcmp(argv[1],"--usage")==0) ||
	 (strcmp(argv[1],"/?")==0) ) {
      fprintf(stderr,"This is eep24c version " EEP_VERSION "\n"
	      "eep24c is free software with ABSOLUTELY NO WARRANTY.\n"
	      "Copyright (c) 2002 - Pedro Zorzenon Neto.\n"
	      "\n"
	      "eep24c: 24Cxxx eeprom utilities.\n"
	      "\n"
	      "Usage examples:\n"
	      "check supported devices   : eep24c -d help\n"
	      "read eeprom, write to file: eep24c -d 24c04 -r file.hex\n"
	      "read file, write to eeprom: eep24c -d 24c04 -w file.hex\n"
	      "read file, write to eeprom: eep24c -d 24c04 -k file.hex\n"
	      "fill eeprom with 0x7A     : eep24c -d 24c04 -f 7A\n"
	      "\n"
	      "'-k' and '-w' are different. values not "
	      "specified in input file will be:\n"
	      "  written as 00 (option '-w') or;\n"
	      "  kept as they were (option '-k').\n"
	      "option '-r' will overwrite file.hex if it exists.\n"
	      "input and output files are IntelHex format.\n"
	      "\n"
	      "You can extend clock pulse times by adding a number\n"
	      "after -r, -w, -k, -f. Example: '-r5' will read device using\n"
	      "clock pulses 5 times slower.\n");
      return 0;
    }
  }

  if ( argc == 3 ) {
    if ( ( strcmp(argv[1],"-d")==0 ) &&
	 ( strcmp(argv[2],"help")==0 ) ) {
      fprintf(stderr,"Supported devices are:\n"
	      "24c01 24c02 24c04 24c08 24c16 24c32 24c64 "
	      "24c128 24c256 24c512 24c515\n");
      return 0;
    }
  }

  if ( argc != 5 ) {
    fprintf(stderr,"Try: eep24c --help\n");
    return 1;
  }

  if ( strcmp(argv[1],"-d")!=0 ) {
    fprintf(stderr,"didn't find '-d' as the first argument.\n");
    return 1;
  }

  par[0]=0; par[4]=0;
  /* IMPORTANT: we will use small write_size parameters because
   * some eeprom manufacturer does not support big values. */
  if ( strcmp(argv[2],"24c01")==0 )
    { par[0]=8; par[1]=1; par[2]=128; par[3]=128; }
  else if ( strcmp(argv[2],"24c02")==0 )
    { par[0]=8; par[1]=1; par[2]=256; par[3]=256; }
  else if ( strcmp(argv[2],"24c04")==0 )
    { par[0]=8; par[1]=1; par[2]=256; par[3]=512; }
  else if ( strcmp(argv[2],"24c08")==0 )
    { par[0]=8; par[1]=1; par[2]=256; par[3]=1024; }
  else if ( strcmp(argv[2],"24c16")==0 )
    { par[0]=8; par[1]=1; par[2]=256; par[3]=2048; }
  else if ( strcmp(argv[2],"24c32")==0 )
    { par[0]=16; par[1]=2; par[2]=4096; par[3]=par[2]; }
  else if ( strcmp(argv[2],"24c64")==0 )
    { par[0]=16; par[1]=2; par[2]=8192; par[3]=par[2]; }
  else if ( strcmp(argv[2],"24c128")==0 )
    { par[0]=32; par[1]=2; par[2]=16384; par[3]=par[2]; }
  else if ( strcmp(argv[2],"24c256")==0 )
    { par[0]=32; par[1]=2; par[2]=32768; par[3]=par[2]; }
  else if ( strcmp(argv[2],"24c512")==0 )
    { par[0]=64; par[1]=2; par[2]=65536; par[3]=par[2]; }
  else if ( strcmp(argv[2],"24c515")==0 )
    { par[0]=32; par[1]=2; par[2]=32768; par[3]=65536; par[4]=1; }

  if (par[0]==0) {
    fprintf(stderr,"Did not find the device '%s'.\n",argv[2]);
    fprintf(stderr,"Try: eep24c -d help\n");
    return 1;
  }

  if ( strncmp(argv[3],"-r",2)==0 ) {
    mode=EEP_READ;
  }
  if ( strncmp(argv[3],"-w",2)==0 ) {
    mode=EEP_WRITE;
  }
  if ( strncmp(argv[3],"-k",2)==0 ) {
    mode=EEP_READWRITE;
  }
  if ( strncmp(argv[3],"-f",2)==0 ) {
    mode=EEP_FILL;
  }

  if ( mode==0 ) {
    fprintf(stderr,"Did not understand '%s'. It was supposed to be "
	    "'-r', '-w', '-k' or '-f'.\n",argv[3]);
    return 1;
  }

  if ( strlen(argv[3]) > 2 ) {
    microdelay_factor = atoi(argv[3]+2);
    if (microdelay_factor < 1) { microdelay_factor = 1; }
    if (microdelay_factor > 50) { microdelay_factor = 50; }
    fprintf(stderr,"Timing Info: multiply times by %d.\n", microdelay_factor);
  }

  eep=eeprom_init(parport_baseaddress(), par[0], par[1], par[2],
		  par[3],par[4],microdelay_factor);
  mem=memory_init(par[3]); /* initialize buffer */

  switch (mode) {
  case EEP_READ:
    eeprom_fullread (eep, mem);
    mem_to_ihex(argv[4], mem);
    break;
  case EEP_WRITE:
    memory_fill (mem, 0x00);
    ihex_to_mem(argv[4], mem);
    eeprom_fullwrite (eep, mem);
    break;
  case EEP_READWRITE:
    eeprom_fullread (eep, mem);
    ihex_to_mem(argv[4], mem);
    eeprom_fullwrite (eep, mem);
    break;
  case EEP_FILL:
    memory_fill (mem, 0xFF & strtol(argv[4],NULL,16));
    eeprom_fullwrite (eep, mem);
    break;
  }

  memory_destroy(mem);
  eeprom_destroy(eep);
  return 0;
}
