/* upload_slow -- by Vince Weaver vince at deater.net       */
/* Will upload a binary from a Linux box to an Apple II     */
/*    with a super-serial card set to 9600 baud.            */
/* Compile with gcc -O2 -Wall -o upload_slow upload_slow.c  */
/* Usage:   upload_slow port offset binary                  */
/* Eg:      upload_slow /dev/ttyS1 0xc00 tb_6502            */
/* If your super serial card is in slot 2, run "IN#2" on    */
/*   the apple side before running upload_slow on the Linux */
/*   side.  It is a hack, because the IN code is very slow  */
/*   a better solution is a small program that runs the     */
/*   super-serial card in interrupt mode.                   */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h> 
#include <termios.h>
#include <stdlib.h>
#include <sys/ioctl.h>


void print_serial_status(int fd) {
   int status;
       ioctl(fd, TIOCMGET, &status);
       printf("Status: ");
       if (status & TIOCM_LE) printf("DSR ");
       if (status & TIOCM_DTR) printf("DTR ");
       if (status & TIOCM_RTS) printf("RTS ");
       if (status & TIOCM_CTS) printf("CTS ");
      if (status & TIOCM_CAR) printf("DCD ");
       
      printf("\n");   
}


void slow_output(unsigned char *buffer, int size,int fd) {
 
   int i;
   int result;   
   
   for (i=0;i<size;i++) {
//       print_serial_status(fd);
       result=write(fd,&buffer[i],1);
       if (result<0) printf("ERROR!\n");
  //     print_serial_status(fd);
      
       usleep(100000);
   }
}

int main(int argc, char **argv) {
 
   int fd,input,start_address,result,i,chars;
   struct termios options;   
   
   
   char out_buffer[256];
   unsigned char in_buffer[256];

   
   if (argc!=4) {
      printf("Usage: %s port offset binary\n",argv[0]);
      exit(1);
   }

   fd = open(argv[1], O_RDWR | O_NOCTTY );
   
   if (fd == -1) {
      printf("Unable to open %s\n",argv[1]);
      exit(1);
   }
   
   fcntl(fd, F_SETFL, 0);
   
   tcgetattr(fd, &options);
   
   cfsetispeed(&options, B9600);
   cfsetospeed(&options, B9600);

//   options.c_cflag |= (CLOCAL | CREAD);
   options.c_cflag |= CREAD;

   options.c_cflag |= CRTSCTS;
    options.c_oflag &= ~OPOST;
   
   tcsetattr(fd, TCSANOW, &options);

   start_address=strtol(argv[2],NULL,0);
   
   out_buffer[0]='\r';
   slow_output(out_buffer,1,fd);
   
   input=open(argv[3],O_RDONLY);
   if (input<0) {
      printf("Error opening %s!\n",argv[3]);
      exit(1);
   }
   
   strncpy(out_buffer,"CALL -151\r",11);
   slow_output(out_buffer,11,fd);

   out_buffer[0]='\r';
   slow_output(out_buffer,1,fd);
   
   
   result=16;
   while(result!=0) {
      result=read(input,in_buffer,16);
      if (result!=0) {
         chars=sprintf(out_buffer,"%X: ",start_address);
	 slow_output(out_buffer,chars,fd);
	 
         for(i=0;i<result;i++) {
	    chars=sprintf(out_buffer,"%.2X ",in_buffer[i]);
	    slow_output(out_buffer,chars,fd);
	 }

         out_buffer[0]='\r';
	 slow_output(out_buffer,1,fd);
         start_address+=16;
      }
   }
   
   out_buffer[0]='\r';
   slow_output(out_buffer,1,fd);
   
   close(fd);
   close(input);
   return 0;
   
}

