// ** Casio Power Graphics backup Utility **
// (c) 17.11.1996 Tomas Beyer
// Source Compiled with SAS_C 6.57
// E-mail: beyer@jackal.cis.vutbr.cz
// S-mail:  Tom Beyer
//          Slavkovska 983
//          Bucovice 685 01
//          Czech Republic

#include <proto/exec.h>
#include <proto/dos.h>
#include <dos/dos.h>
#include <devices/serial.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define ERR 0
#define OK  1

#define HEAD 0
#define BODY 40

#define CODE_INIT_NOSERIAL  -1
#define CODE_INIT_NOPORT    -1
#define RAMTOP  32768

struct  MsgPort *ComPort;

struct  IOExtSer *SerialIN, *SerialOUT;

FILE    *file;

int     ReturnCode;
char    name[20];

BOOL    trn = FALSE; pgm = FALSE;

UBYTE   scmd;
UBYTE   *p_buffer;
UBYTE   header[40];
UBYTE   io_Error = 0, chsum, tmp, id;
UWORD   i, lenght;
ULONG   offset;

int     RCVProgram( void);
int     WContact( void);
int     GetHeader( void);
int     GetBody( ULONG lenght);
int     SendOK( void);
UBYTE   Chsum( UWORD len);
void    ClearSerial( void);
void    Send(UBYTE *DataPtr,ULONG Length);
void    Request(UBYTE *DataPtr,ULONG RemainChars);
UBYTE   DoChsum( UWORD len);
int     PutBody( ULONG lenght);
int     PutHeader( void);
int     SContact( void);
int     WaitOK( void);
int     EndCom( void);
int     MakeEditorFile( void);


int MakeEditorFile( void)
 {
  offset = 41;

  i=0;

  while((p_buffer[i+offset] = getc( file)) != EOF)
   {
    if(p_buffer[ i+offset] == 0x0A)
      p_buffer[ i+offset] = 0x0D;

    i++;
   }

  i-=1;

  p_buffer[offset-1] = ':';
  p_buffer[i+offset] = 0xff;

  offset = 0;

  p_buffer[ offset+0] = ':';
  p_buffer[ offset+1] = 'E';
  p_buffer[ offset+2] = 'N';
  p_buffer[ offset+4] = (i+3) / 256;
  p_buffer[ offset+5] = (i+3) & 0x00ff;
  p_buffer[ offset+3] = p_buffer[offset+6] = p_buffer[offset+7] = 0;

  printf("Enter filename( max.12):");
  scanf("%12s", name);
  memcpy( &p_buffer[offset+8], &name[0], strlen( name));

  return( OK);
}

int RCVProgram( void)
 {
  if(WContact() == ERR)
    return ( ERR);

  offset = HEAD;

  if(GetHeader() == ERR)
    return ( ERR);

  if(p_buffer[1] != id)
    return ( ERR);

  lenght = p_buffer[4] * 256 + p_buffer[5];

  SendOK();

  offset = BODY;

  if(GetBody( lenght) == ERR)
    return ( ERR);

  SendOK();

  return( OK);
 }

int TRNProgram( void)
 {
  offset = HEAD;

  if(p_buffer[ offset+1] != id)
    return ( ERR);


  if(SContact() == ERR)
    return ( ERR);

  if(PutHeader() == ERR)
    return ( ERR);

  lenght = p_buffer[4] * 256 + p_buffer[5];

  WaitOK();

  offset = BODY;

  if(PutBody( lenght) == ERR)
    return ( ERR);

  WaitOK();

  return( OK);
 }


int WContact( void)
 {
  Request( &tmp, 1L);
  if(tmp != 22)
    return( ERR);
  scmd = 19;
  Send( &scmd, 1L);
  return( OK);
 }

int SContact( void)
 {
  scmd = 22;
  Send( &scmd, 1L);
  Request( &tmp, 1L);
  if(tmp != 19)
    return( ERR);
  return( OK);
 }

int GetHeader( void)
 {
  Request( &p_buffer[offset], 40L);

  if(Chsum(39) == ERR)
    return (ERR);

  return( OK);
}

int PutHeader( void)
 {
  DoChsum(39);
  Send( &p_buffer[offset], 40L);
  return( OK);
 }


int GetBody( ULONG lenght)
 {
  Request( &p_buffer[offset], lenght);

  if(Chsum(lenght-1) == ERR)
    return( ERR);

  return( OK);
 }

int PutBody( ULONG lenght)
 {
  DoChsum(lenght-1);
  Send( &p_buffer[offset], lenght);
  return( OK);
 }

int SendOK( void)
 {
  scmd = 6;
  Send( &scmd, 1L);
  return( OK);
 }

int WaitOK( void)
 {
  Request( &tmp, 1L);
  printf("Host returned %02X.\n", tmp);
  return( OK);
 }

UBYTE Chsum( UWORD len)
 {
  chsum = p_buffer[offset];

  for( i = 0; i<len; i++)
    chsum -= p_buffer[i+offset];

  if(chsum != p_buffer[i+offset])
    return( ERR);

  return( OK);
 }

UBYTE DoChsum( UWORD len)
 {
  chsum = p_buffer[offset];

  for( i = 0; i<len; i++)
    chsum -= p_buffer[i+offset];

  p_buffer[i+offset] = chsum;

  return( OK);
 }

void Request(UBYTE *DataPtr,ULONG RemainChars)
 {
  SerialIN->IOSer.io_Command=CMD_READ;
  SerialIN->IOSer.io_Length=RemainChars;
  SerialIN->IOSer.io_Data=(APTR)DataPtr;
  SerialIN->IOSer.io_Flags|=IOF_QUICK;

  DoIO((struct IORequest *)SerialIN);
 }

void Send(UBYTE *DataPtr,ULONG Length)
 {
  SerialIN->IOSer.io_Command=CMD_WRITE;
  SerialIN->IOSer.io_Length=Length;
  SerialIN->IOSer.io_Data=(APTR)DataPtr;
  SerialIN->IOSer.io_Flags|=IOF_QUICK;

  DoIO((struct IORequest *)SerialIN);
 }

void ClearSerial( void)
 {SerialIN->IOSer.io_Command=CMD_CLEAR;
  SerialIN->IOSer.io_Flags|=IOF_QUICK;

  DoIO((struct IORequest *)SerialIN);
 }

int InitCom( void)
 {
  if (!(ComPort=CreatePort(0,0)))
    return( ERR);

  if (!(SerialIN=(struct IOExtSer *)CreateExtIO(ComPort,sizeof(struct IOExtSer))))
    return( ERR);

  if (OpenDevice(SERIALNAME,0L,(struct IORequest *)SerialIN,0))
   {
    io_Error=SerialIN->IOSer.io_Error;
    DeleteExtIO((struct IORequest *)SerialIN);
    SerialIN=NULL;
    return( ERR);
   }

  SerialIN->io_RBufLen=0x4000;
//  SerialIN->io_Baud=1200;
  SerialIN->io_TermArray.TermArray0=0xFFFEF8F7;
  SerialIN->io_TermArray.TermArray1=0xF0F0F0F0;
  SerialIN->io_SerFlags|=SERF_RAD_BOOGIE|SERF_XDISABLED;
  SerialIN->IOSer.io_Command=SDCMD_SETPARAMS;

  if(DoIO((struct IORequest *)SerialIN) != NULL)
    return( ERR);

  return( OK);
 }

int EndCom( void)
 {
  fclose( file);

  AbortIO((struct IORequest *)SerialIN);
  WaitIO((struct IORequest *)SerialIN);

  if (SerialIN)
   {
    CloseDevice((struct IORequest *)SerialIN);
    DeleteExtIO((struct IORequest *)SerialIN);
   }

  if (SerialOUT)
    DeleteExtIO((struct IORequest *)SerialOUT);

  DeletePort(ComPort);

  free( (void *)p_buffer);

  return(0);
}


main( int argc, char *argv[])

 {
  printf("** CASIO Power Graphics Backup utility v.0.9ß **\n(c)10.5.1996 Tomas Beyer. All rights reserved.\n\n");

  if(argc != 4)
   {
    printf("USAGE:\tcasio <r|t> <e|p|f> <file>\n\n");
    printf("\tr - receive\n\tt - transmit\n\n\te - editor file\n\tp - program\n\tf - Amiga file (eg. GoldED) into file editor\n\n");
    exit( 10);
   }

  if( strcmp(argv[1], "t") == NULL)
    trn = TRUE;

  if( strcmp(argv[2], "p") == NULL)
    id = 'P';

  if( strcmp(argv[2], "e") == NULL)
    id = 'E';

  if( strcmp(argv[2], "f") == NULL)
    id = 'F';

  if ((p_buffer = (UBYTE *) malloc (sizeof(UBYTE) * RAMTOP)) == NULL)
   {
    printf("Not enough memory to alocate buffer.\n");
    exit(10);
   }

  if(InitCom() == ERR)
   {
    printf("Error while opening serial.\n");
    free( (void *) p_buffer);
    exit(10);
   }

  for(i=0; i<32767;i++)
    p_buffer[i]=0xFF;

  if(trn == TRUE && id == 'F')
   {
    id='E';

    if((file = fopen ( argv[argc-1], "rb")) == NULL)
     {
      printf("Error while opening file.\n");
      EndCom();
      exit(10);
     }

    MakeEditorFile();
    printf("Transmitting...\n");
    lenght=p_buffer[4] * 256 + p_buffer[5];
    printf("File length: %d bytes.\n", lenght-3);

    if( TRNProgram() == ERR)
     {
      printf("Error while transmit.\n");
      EndCom();
      exit(10);
     }
    id='F';
   }

  if(trn == TRUE && (id == 'P' || id == 'E'))
   {
    if((file = fopen ( argv[argc-1], "rb")) == NULL)
     {
      printf("Error while opening file for input.\n");
      EndCom();
      exit(10);
     }

    printf("Transmitting...\n");

    offset = 0;

    for(i=0;i<40;i++)
      p_buffer[i+offset] = getc( file);

    offset = 40;

    lenght = p_buffer[4] * 256 + p_buffer[5];
    printf("File length: %d bytes.\n", lenght-3);

    for(i = 0; i < lenght; i++)
      p_buffer[i+offset] = getc( file);

    if( TRNProgram() == ERR)
     {
      printf("Error while transmit.\n");
      EndCom();
      exit(10);
     }
   }


  if(trn == FALSE)
   {
    printf("Receiving...\n");

    if( RCVProgram() == ERR )
     {
      printf("Error while receiving..\n");
      EndCom();
      exit(10);
     }

    printf("File length: %d\n", lenght-3);

    if((file = fopen ( argv[argc-1], "wb")) == NULL)
     {
      printf("Error opening file for output..\n");
      EndCom();
      exit(10);
     }

    for(i = 0; i < (lenght+40); i++)
      putc( p_buffer[i], file);
   }

  EndCom();
  printf("Everything's right...\n");
  return( OK);
 }
