/*-------------------------------------------------------------------------*/
/* FILENAME: flash.c -- DSK - HOST Code                                    */
/*                                                                         */
/*  Rev 2.10   07 Jun 2000  Z.Zhang, T.J.Dillon                            */
/*                                                                         */
/*-------------------------------------------------------------------------*/
/*  HISTORY                                                                */
/*  Rev 1.00   Created by Z.Zhang                                          */
/*  Rev 2.00   Update for C6711 DSK to include user command line options   */
/*  Rev 2.01   Added error detection for hex formats                       */
/*  Rev 2.02   Added command line filename, test for flash page boundary   */
/*  Rev 2.03   Corrected error in number of characters for filename        */
/*  Rev 2.10   Updated for larger SDRAM                                    */
/*                                                                         */
/*-------------------------------------------------------------------------*/

#include <stdio.h>
#include <windows.h>
#include "dsk6211.h"
#include "c6211dsk.h"
                                      
#define DSP_BUFFER_ADDR 0x200
#define PWD  0x12345678
#define DISPLAY_SIZE 10
 
static  FILE *hex_fp=NULL;

BOOL	FILEDefined=FALSE;  
BOOL	InfoOnly=FALSE;
BOOL	ADDRDefined=FALSE;  

/*-------------------------------------------------------------------------*/
/* main()                                                                  */
/*-------------------------------------------------------------------------*/

void main(int argc1, char *argv1[])
{
  dskHANDLE hBd;		/* Board device handle                             */
  short  iBd    = 0;    /* Board index                                     */
  BOOL   bExcl  = 1;    /* Exclusive open = TRUE                           */
  char coffNam[20]= "flash_prog.out";
                        /* COFF file name                                  */
  BOOL bVerbose = 0;    /* COFF load verbose mode = FALSE                  */
  BOOL bClr     = 0;    /* Clear bss mode = FALSE                          */
  BOOL bDump    = 0;    /* Dump mode = FALSE                               */

  char hex_filename[40]="\0";
  unsigned long host_buffer[33];

  ULONG nPort=0xa;
  unsigned long length;
  int flag, data_flag, i, j, data, header;
  unsigned long checksum, flash_addr=0x90000000, display_count;
  unsigned char *data_ptr;
  char Change[4]="\0";

  /*-----------------------------------------------------------------------*/
  /* Parse Command Line                                                    */
  /*-----------------------------------------------------------------------*/
  for(i=1; argc1 > i; i++)
  {
    if( argv1[i][0] != '-' )
    {
      strncpy(hex_filename,argv1[i],39);
      FILEDefined=TRUE;
    }
    else
    {
      switch(tolower(argv1[i][1]))
      {
        case 'h':
        case '?':
          printf( "Syntax: flash [-?] [-pport] [-saddr] [filename]\n");
          printf( "\n");
          printf( "  -?,h   : Displays command line help info.\n");
          printf( "  -pport : Specifies board to test (a,b,c or d).\n");
          printf( "  -saddr : Defines start addr to program flash.\n");
          printf( "filename : Name of hex file to program flash.\n\n");
          printf( "NOTE: This utility works with ASCII-Hex files ONLY!\n");
          printf("\nTMS320C6211/6711 DSK Flash Programming Utility ");
          printf("Version 2.10,  Jun 2000");
          printf("\nCopyright (c) 2000 ");
          printf("by Texas Instruments Incorporated. ");
          printf("\nAll rights reserved.\n\n");
		  InfoOnly=TRUE;
          break;
        case 'p':
          switch(tolower(argv1[i][2]))
          {
            case 'a':
              nPort=0xa;
              break;
            case 'b':
              nPort=0xb;
              break;
            case 'c':
              nPort=0xc;
              break;
            case 'd':
              nPort=0xd;
              break;
            default:
              nPort=0xa;
              break;
          }
		  break;
        case 's':
          sscanf(&argv1[i][4],"%x",&flash_addr);
		  ADDRDefined=TRUE;
          break;
        default:
          printf( "\nOPTION (-%c) IGNORED: \n  Valid options are -?,-h,-pport and -saddr!\n",argv1[i][1]);
          break;
      }
    }
  }

  /*-----------------------------------------------------------------------*/
  /* Quit if -h or -? option used                                          */
  /*-----------------------------------------------------------------------*/
  if(InfoOnly)
	  exit(99);

  /*-----------------------------------------------------------------------*/
  /* Print Program header                                                  */
  /*-----------------------------------------------------------------------*/
  printf("\nTMS320C6211/6711 DSK Flash Programming Utility");
  printf(", Version 2.10,  Jun 2000 ");
  printf("\nCopyright (c) 2000 ");
  printf("by Texas Instruments Incorporated. ");
  printf("All rights reserved.\n\n");

  /*-----------------------------------------------------------------------*/
  /* Request name of .hex file                                             */
  /*-----------------------------------------------------------------------*/
  if(!FILEDefined)
  {
	printf ("\nInput the name of the .hex file to be programmed in flash:\n");
	scanf ("%s", &hex_filename);
  }

  /*-----------------------------------------------------------------------*/
  /* Append .hex to filename (if missing)                                  */
  /*-----------------------------------------------------------------------*/
  if(strchr( hex_filename, '.') == NULL)
	  strcat( hex_filename, ".hex");

  /*-----------------------------------------------------------------------*/
  /* Request start address                                                 */
  /*-----------------------------------------------------------------------*/
  if(!ADDRDefined)
  {
	printf("\nDefault Start Address to program flash=0x%x \n",flash_addr);
	printf("  Do you want to keep it? (Yes/No): "); /* Yes to keep default */
	scanf("%s",Change);

	if(!strncmp("Yes",Change,1) || !strncmp("yes",Change,1))
	{    /* Keep default    */
	}
	else /* Enter new value */
	{
	  printf("Input Start Address to program flash: ");
	  scanf("%x",&flash_addr);
	}
  }

  /*-----------------------------------------------------------------------*/
  /* Test for start address within range of FLASH                          */
  /*-----------------------------------------------------------------------*/
  if ( flash_addr < 0x90000000 )
  {
	  printf ("\nERROR: Start address < 0x90000000!\n");
	  exit(0);
  }
		  
  if (flash_addr >= 0x90020000)
  {
	 printf ("\nERROR: Start address > 0x90020000!\n");
	 exit(0);
  }

  if (flash_addr % 0x80)
  {
	 printf ("\nERROR: Start address not on 0x80 page boundary!\n");
	 exit(0);
  }

  /*-----------------------------------------------------------------------*/
  /* Test for filename                                                     */
  /*-----------------------------------------------------------------------*/
  if ( (hex_fp=fopen( hex_filename, "r" ))== NULL )
  {
     printf( "\nERROR: File %s does not exist!\n\n", hex_filename );
     exit(0);
  }

  /*-----------------------------------------------------------------------*/
  /* Open a driver connection to a dsk6x board.                            */
  /*-----------------------------------------------------------------------*/
  if ( !dsk6x_open(nPort,&hBd) ) 
  {
	  printf ("FAILED: dsk6x_open()!\n");
	  exit(1);
  }

  /*-----------------------------------------------------------------------*/
  /* Cause a DSP reset.                                                    */
  /*-----------------------------------------------------------------------*/
  if ( !dsk6x_reset_dsp(hBd,0,1) )
  {
	  printf ("FAILED: dsk6x_reset_dsp()!\n");
	  exit(2);
  }

  /*-----------------------------------------------------------------------*/
  /* Establish a connection to the HPI of a target board.                  */
  /*-----------------------------------------------------------------------*/
  if ( !dsk6x_hpi_open(hBd))
  {
	  printf ("FAILED: dsk6x_hpi_open()!\n");
	  exit(3);
  }

  /*-----------------------------------------------------------------------*/
  /* Read a COFF file and write the data to DSP memory.                    */
  /*-----------------------------------------------------------------------*/
  if (dsk6x_coff_load(hBd,coffNam,bVerbose,bClr,bDump))
  {
	  printf("FAILED: dsk6x_coff_load()!\n");
	  exit(4);
  }
 
  /*-----------------------------------------------------------------------*/
  /* Generate a DSPINT to start program                                    */
  /*-----------------------------------------------------------------------*/
  if (!dsk6x_hpi_generate_int(hBd)) 
  {
	  printf("FAILED: dsk6x_hpi_generate_int()!\n");
	  exit(5);
  }

  length = 4; /* 4 bytes for 1 word */
  flag =0;

  /*-------------------------------------------------------------------*/
  /* wait till dsp is ready.                                           */
  /*-------------------------------------------------------------------*/
  while (flag == 0)
  {
      /*---------------------------------------------------------------*/
      /* Read data from dsp                                            */
      /*---------------------------------------------------------------*/
	  if (!dsk6x_hpi_read(hBd, host_buffer, &length, 
        DSP_BUFFER_ADDR) || length != 4)
      { /* evm6x_hpi_read() failed */
		    continue; // try again
      }

	  /*---------------------------------------------------------------*/
	  /* Test if dsp is ready                                          */
	  /*---------------------------------------------------------------*/
	  if(host_buffer[0] == PWD) flag = 1;  
  } 
 
  /*-------------------------------------------------------------------*/
  /* Send handshaking back to DSP                                      */
  /*-------------------------------------------------------------------*/
  length = 4;
  host_buffer[0] = 0;
  host_buffer[1] = flash_addr;
   
  if (!dsk6x_hpi_write(hBd, &host_buffer[1], &length, 
        DSP_BUFFER_ADDR + 4) || length != 4)
  { 
	  printf("ERROR: dsk6x_hpi_write() - flash address!\n");
	  exit(0);
  }

  if (!dsk6x_hpi_write(hBd, &host_buffer[0], &length, 
        DSP_BUFFER_ADDR) || length != 4)
  { 
	  printf("ERROR: dsk6x_hpi_write() - handshake flag!\n");
	  exit(0);
  }


  /*-------------------------------------------------------------------*/
  /* Send DSP Packets to program the FLASH                             */
  /*-------------------------------------------------------------------*/
  data_flag = 0;
  checksum = 0;
  display_count = 0;
  if ( (header=fgetc(hex_fp)) == 0x02)
  {  // do nothing
  }
  else
  {
	  printf("ERROR: ASCII-Hex format required by Flash Utility!\n");
	  printf("  Hex file format=");
	  if(header==0x3A)
	  {
		  printf("Intel MCS-86 format (hex6x -i).\n");
	  }
	  else if(header==0x53)
	  {
		  printf("Motorola Exorciser format (hex6x -m).\n");
	  }
	  else if(header==0x4B)
	  {
		  printf("TI SDSMAC format (hex6x -t).\n");
	  }
	  else if(header==0x25)
	  {
		  printf("Extended Tektronix format (hex6x -x).\n");
	  }
	  else
	  {
		  printf("Unknown format ** Header=0x%x!\n",header);
	  }
	  
	  printf("SOLUTION: Rerun hex conversion with ASCII-Hex format (hex6x -a)!!\n");
	  exit(0);
  }
/*  fgetc(hex_fp); * skip the header character in the file */
  printf("Programming the flash.");
  while (data_flag == 0)
  {
	  display_count++;
	  if ( display_count == DISPLAY_SIZE)
	  {
		  display_count = 0;
		  printf (".");
	  }
	  
	  data_ptr = (unsigned char *)&host_buffer[1];
	  for (i =0;i<FLASH_WRITE_SIZE;i++) 
	  {
		  j = fscanf(hex_fp,"%x", &data);
		  *data_ptr = data;
		  checksum += (unsigned int)*data_ptr++;
		  if (j == EOF || j == 0)
		  {
			  data_flag = 1;
		  }
		  flash_addr += 1;
		  if (flash_addr > 0x90020000)
		  {
			  printf ("ERROR: dsk6x_hpi_write() - beyond valid flash address!\n");
			  exit(0);
		  }

	  }

	  if(data_flag == 0)
	  {
		  length = FLASH_WRITE_SIZE;
          if (!dsk6x_hpi_write(hBd, &host_buffer[1], &length, 
             DSP_BUFFER_ADDR+4) || length != 128)
		  { 
	          printf("ERROR: dsk6x_hpi_write() - host packet!\n");
	          exit(0);
		  }
	  }

	  length = 4;
	  if (data_flag == 0) host_buffer[0] = 1;
	  else host_buffer[0] = 2;
     
	  if (!dsk6x_hpi_write(hBd, host_buffer, &length, 
        DSP_BUFFER_ADDR) || length != 4)
	  { 
	     printf("ERROR: dsk6x_hpi_write() - host packet command 1!\n");
	     exit(0);
	  }
 
	  flag =0;
      while (flag == 0)
	  {
    	 if (!dsk6x_hpi_read(hBd, host_buffer, &length, 
           DSP_BUFFER_ADDR) || length != 4)
		 { /* evm6x_hpi_read() failed */
		    continue; // try again
		 }
	     if(host_buffer[0] == 0) flag = 1;
	  } 

  }

  length = 4;
  host_buffer[0] = 1;
      
  if (!dsk6x_hpi_write(hBd, host_buffer, &length, 
        DSP_BUFFER_ADDR) || length != 4)
  { 
     printf("ERROR: dsk6x_hpi_write() - host packet command 2!\n");
     exit(0);
  }

  length = 8; /* 4 bytes for 1 word */
  flag =0;

  while (flag == 0)
  {
  	  if (!dsk6x_hpi_read(hBd, host_buffer, &length, 
        DSP_BUFFER_ADDR) || length != 8)
      { /* evm6x_hpi_read() failed */
		    continue; // try again
      }

	  if(host_buffer[0] == PWD) flag = 1;  
  } 
  
  /*-------------------------------------------------------------------*/
  /* Finish up                                                         */
  /*-------------------------------------------------------------------*/
  printf ("\n");
  if (checksum == host_buffer[1]) 
	  printf("Flash successfully programmed!\n");
  else 
	  printf("ERROR: Checksum does not match!\n");

  /*-------------------------------------------------------------------*/
  /* Close hex file                                                    */
  /*-------------------------------------------------------------------*/
  fclose(hex_fp);
}