/*
          grab.c
         --------

   Compile: gcc -o grab grab.c

   The Linux side of the Epson HX20 binary data transfer. Takes filename
   as parameter, then stores the data received from DUMP.BAS on the Epson side.

   (c) Martin Woelz 2000    eMail: woelz@math.uni-goettingen.de

*/

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>


#define portname "/dev/ttyS0"
#define max      252             /* In line 70 of the BASIC program DUMP.BAS,
				    a max of 252 may be specified to make full
				    use of the 255 byte serial output buffer.
				    However it is safer to use less because the
				    arithmetics are weird in HX20 BASIC.     */
/* Some global variables */
int fd;        /* reference to serial port for termios library calls */
struct termios oldtio, newtio;   /* two sets of serial port settings */

/* Prototypes */
int serial_init(void);
void serial_reset(void);

int main(int no_arg, char *argv[])
{
  FILE* targetfile;
  char buffer[max];
  unsigned char n;
  unsigned short int sum, nlcr;
  int i, b = 0;
  
  if (no_arg != 2)
    {
      fprintf(stderr, "Usage: %s 'filename'\n", argv[0]);
      return 1;
    }
  if (serial_init() != 0)
    {
      fprintf(stderr, "%s: Couldn't open serial port %s\n", argv[0], portname);
      return 1;
    }

  targetfile = fopen(argv[1], "w");

  /* Synchronize */
  printf("Listening...");
  fflush(stdout);
  do {                           /* wait for 'A' */
    read(fd, buffer, 1);
  } while (buffer[0] != 'A');
  read(fd, &nlcr, 2);            /* discard NL-CR */
  write(fd, buffer, 1);          /* reply 'A'    */

  /* Main Loop */
  read(fd, &n, 1);
  while (n != 0)
    {
      read(fd, buffer, n);
      read(fd, &sum, 2);
      read(fd, &nlcr, 2);           /* discard NL-CR */
      
      for(i = 0; i < n&0xff; i++)
	{
	  fputc(buffer[i], targetfile);
	  sum -= buffer[i]&0xff;
	}
      printf("\r%d Bytes read", b += n&0xff);
      fflush(stdout);
      if (sum != 0 || nlcr != 0x0a0d)
	{
	  fprintf(stderr, "\n%s: Checksum error\n", argv[0]);
	  fclose(targetfile);
	  serial_reset();
	  return 1;
	}
      read(fd, &n, 1);
    }

  putchar('\n');
  fclose(targetfile);
  serial_reset();
  return 0;
}


int serial_init(void)
{
  fd = open(portname, O_RDWR | O_NOCTTY);        /* open on system level */
  if ((fd<0) || !isatty(fd))
    return 1;
  
  tcgetattr(fd,&oldtio);         /* save current port settings              */
  newtio.c_cflag = B4800 | CS8 | CREAD | CLOCAL | CRTSCTS;
  newtio.c_iflag = 0;
  newtio.c_oflag = 0;
  
  /* On Epson HX20, this corresponds to "COM0:(68N13)" */

  /* set input mode (non-canonical, no echo,...) */
  newtio.c_lflag = 0;
  
  newtio.c_cc[VTIME]    = 1;     /* give the Epson some time to think       */
  newtio.c_cc[VMIN]     = max;   /* read whole buffer at one time           */
  
  tcflush(fd, TCIOFLUSH);        /* flush all data */
  tcsetattr(fd,TCSANOW,&newtio); /* set new attributes                      */

  return 0;
} /* end serial_init */


void serial_reset(void)
{
  /*tcflush(fd, TCIOFLUSH);*/        /* flush all data (maybe not necc)*/
  tcsetattr(fd,TCSANOW,&oldtio);
  close(fd);
} /* end serial_reset */

