/* ALink85 by Shawn D'Alimonte (aa600@torfree.net)                      */
/* Based on:                                                            */
/* XLink85  -  TI85<->PC  link  program,  Copyright (c) 1996 Jani Halme	*/
/* My work is mostly in tiport.c, which is the low level port access    */
/* routines.  The rest is by Jani Halme, but has been reorganized.      */
/*                                                                      */
/* !!!!!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!       */
/*                                                                      */
/* This program uses the CIA registers directly without telling the OS  */
/* Therefore it will interfere with and be interefered by an serial and */
/* possiblly parallel port activity.  Also it will not function on any  */
/* possible future Amiga's unless the serial port handshaking bits stay */
/* put.  It will not work with any add-on serial cards                  */
/*									*/
/* 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;  it  now,  write  to  the  Free Software	*/
/* Foundation, Inc., Mass Ave, Cambridge, MA02139.			*/
/*									*/  
/* The author can be contacted by email at:aa600@torfree.net*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "tiport.h"
#include "packet.h"
#include "recv85.h"
#include "version.h"

extern const char identifier[8];
extern const char var_extensions[31][5];
extern const char var_types[31][6];
extern unsigned char *buffer;
extern unsigned short last_packet_size;
extern const char identifier[8];

int sendgroup(char filename[255])
{
	FILE *var_file=NULL;
	UWORD checkbytes, checksum, checksum2, var_length, i, varcnt, hdr_len;
	unsigned char var_type;
	unsigned char var_namelength;
	char var_name[9];
	unsigned long var_offset;
	
	varcnt=0;
	var_file=fopen(filename, "rb");
	fread(buffer, sizeof(char), 8, var_file);
	if (memcmp(buffer, &identifier, 3)==0)
	  {
	    fseek(var_file, 0x35, 0);
	    fread(&checkbytes, sizeof(UWORD), 1, var_file);
	    fread(buffer, sizeof(char), WORDSWAP(checkbytes), var_file);
	    checksum=0;
	    for(i=0;i<WORDSWAP(checkbytes);i++) checksum+=buffer[i];
	    checksum=checksum & 65535;
	    fread(&checksum2, sizeof(UWORD), 1, var_file);
#ifdef DBG
	    printf("Checksum: %x Checksum2: %x\n Checkbytes: %x\n", checksum, checksum2,checkbytes);
#endif
	    /* var_offset points to start of first group entry */
	    var_offset=0x37;
	    checksum=WORDSWAP(checksum);
	    if (checksum==checksum2)
	      {
		/* backup or variable? */
		fseek(var_file, 0x3b, SEEK_SET);
		fread(&var_type, sizeof(char), 1, var_file);
		if (var_type==0x1d)
		  {
		    /* send backup image to calculator */
		    printf("send85: Sending system back<up from '%s'\n", filename);
		    fseek(var_file, 0x37, SEEK_SET);
		    fread(&hdr_len, sizeof(short), 1, var_file);
		    fread(buffer, sizeof(char), WORDSWAP(hdr_len), var_file);
#ifdef DBG
		    printf("Sending backup header....\n hhdr_len: %x\n ",hdr_len);
#endif
		    put_packet(PAK_VARHEADER, hdr_len);
		    if (get_packet()!=PAK_REQDATA)
		      {
			printf("send85: Calculator refused to receive system backup!\n");
			exit(-1);
		      }
		    put_packet(PAK_ACKNOWLEDGE, 0);
		    
		    /* send backup data packets */
		    printf("Sending backup data...\n");
		    for(i=0;i<3;i++)
		      {
			fread(&hdr_len, sizeof(short), 1, var_file);
			fread(buffer, sizeof(char), WORDSWAP(hdr_len), var_file);

#ifdef DBG
			printf("hdr_len: %x\n",hdr_len);
#endif
			put_packet(PAK_DATAPART, hdr_len);
		      }
		    printf("send85: Backup transfer OK!\n");
		    fclose(var_file);
		    exit(0);
		    /* exit here, so no PAK_LASTVAR will be sent */
		  }
		else do
		  {
		    fseek(var_file, var_offset+4, SEEK_SET); 
		    fread(&var_type, sizeof(char), 1, var_file); 
		    fread(&var_namelength, sizeof(char), 1, var_file);
		    fread(&var_name, sizeof(char), var_namelength, var_file); 
		    var_name[var_namelength]=0;
		    fread(&var_length, sizeof(short), 1, var_file);
		    /* send variable header */
		    printf("send85: Sending %8s, type %5s, from %12s\n", 
			   var_name, var_types[var_type], filename);
#ifdef DBG
		    printf("namelength: %x length: %x\n",var_namelength,var_length);
#endif
		    buffer[0]=(var_length >> 8); 
		    buffer[1]=(var_length & 255);
		    buffer[2]=var_type; 
		    buffer[3]=var_namelength;
		    memcpy(buffer+4, &var_name,var_namelength);
		    put_packet(PAK_VARHEADER, ((UWORD)(var_namelength+4))<<8);
		    
		    i=get_packet();
		    switch (i)
		      {
		      case PAK_REQDATA:
			{
#ifdef DBG
			  printf("ACK\n");
#endif
			  put_packet(PAK_ACKNOWLEDGE, 0);
			  /* send variable data */
			  fread(buffer, sizeof(char), WORDSWAP(var_length), var_file);
#ifdef DBG
			  printf("Data part\nvar_length: %x\n",var_length);
#endif
			  put_packet(PAK_DATAPART, var_length);
			  printf("send85: OK!\n");
			  varcnt++;
			  break;
			}
		      case PAK_SKIPVAR:
			{
			  fseek(var_file, var_length, SEEK_CUR);
			  switch (buffer[0])
			    {
			    case 2: printf("send85: Variable skipped!\n"); break;
			    case 1: printf("send85: Transfer aborted by calculator!\n"); exit(-1);
			    case 3: printf("send85: Calculator out of memory!\n"); exit(-1);
			    default: printf("send85: Transfer failed!\n"); exit(-1);
			    }
			  break;
			}
		      default:
			{
			  printf("Invalid ACK packet!\n");
			  exit(-1);
			}
		      }
		    var_offset=ftell(var_file);
		  } 
		while (var_offset<(0x37+WORDSWAP(checkbytes)));
		fclose(var_file);
	      }
	    else
	      {
		printf("send85: Grouped file has incorrect checksum!\n");
		exit(-1);
	      }
	  }
	return varcnt;
      }

int main(argc, argv) int argc;	char **argv;
{
	int i, ii;
	struct stat statbuf;

	printf(VERSION_HDR);

	if (!(buffer=malloc(64*1024*sizeof(UBYTE))))
	  {
	    printf("\aWhat the ...?  No more memory!\n");
	    abort();
	  }
 	
	initport();
	if (argc>1)
	{
		ii=0;
		for (i=1;i<argc;i++)
		{
			if (stat(argv[i], &statbuf)==0)		
				ii+=sendgroup(argv[i]);
			else 
				printf("send85: File '%s' does not exist!\n", argv[i]);
		}
		/* no more variables... */
		if (ii>0)
		{
			put_packet(PAK_LASTVAR, 0);
			i=get_packet();		
		}
		printf("send85: %d variables sent\n", ii);
		free(buffer);
	} else printf("send85: No files specified - aborting!\n");
}
