/* tiport.c - Low level communications routines for TI85 on       */
/*            $4 serial link.  Some bit repositioning              */
/*            to allow use of IBM link routines.                */
/* send() and recv() are based on the send() and recvbyt()        */
/* routines contained in Per Finander's tiproto.txt file          */
/* Shawn D'Alimonte May 17, 1997                                  */
/* Copyright ©1997 Shawn D'Alimonte  Covered by GNU General Picense */
#include "tiport.h"
#include <stdio.h>

/* Looks like we need a delay for faster amigas! */
long DELAY=0;

/* For timeout routines */
#include <time.h>
static clock_t start_time;

/*Bomb out after 1 minute*/
#define TIMEOUT 60.0

/* reset timeout counter */
void timereset(void)
{
  start_time=time(NULL);
}


/* test if the transfer has timed out */
void timetest(void) 
{
  if(difftime(time(NULL),start_time)>TIMEOUT)
    {
      printf("Timeout!  Aborting.\n");
      abort();
    }
}

/* Delay routine */
void SlowDown(void)
{
  int i=0;
  for(;i<DELAY;i++);
}

/* Setup access to CIA's for serial port */
#include <hardware/cia.h>
extern struct CIA ciaa,ciab;

/* Reserve serial port for low level access */
#include <exec/types.h>
#include <exec/memory.h>
#include <resources/misc.h>
#include <clib/exec_protos.h>
#include <clib/misc_protos.h>

struct Library *MiscBase = NULL;

int GotPort = FALSE; // Port reserved

/* val: bit0 = DTR. bit1=RTS */
void  setport(UBYTE val)
{
  UBYTE val2 =(3-val)&0x03;
 ciab.ciapra = (val2&0x01)<<7|(val2&0x02)<<5;

#ifdef DEBUG
  printf("setport sending %x\n",val);
#endif
  
}

/* Returns values of CTS and DSR lines */
/* bit0=cts, bit1=dsr */
/* Amiga CTS = bit4, DSR = bit3*/
UBYTE getport(void)
{
  UBYTE val; 
  val = ciab.ciapra & 0x18;
  
#ifdef DEBUG
  printf("getport: port contains %x\n", val);
#endif
  
  val = (val & 0x10)>>4|(val & 0x08)>>2; 
  val = 3-val;
#ifdef DEBUG
  printf("getport returning %x\n",val);
#endif
  return val;
}

/* Initialize port */
void initport(void)
{
  UBYTE *owner=NULL;

#ifdef DEBUG
  printf("Initializing port\n");
#endif
  if (!(MiscBase= (struct Library *)OpenResource(MISCNAME)))
    printf("Cannot open %s\n",MISCNAME);
  else
    {
      if ((owner=AllocMiscResource(MR_SERIALPORT,"Alink/85"))==NULL)
	{
	  if ((owner=AllocMiscResource(MR_SERIALBITS,"Alink/85"))==NULL)
	    {
	      atexit(GetOut);
	      GotPort = TRUE;
	      DELAY=atol(getenv("ALINK_DELAY"));

	      ciaa.ciaddrb = 0xc0;
	      setport(3);                    /* Keep calc from slowing*/
	    }
	  else
	    {
	      printf("\nSerial port in use by %s\n",owner);
	      
	      /* Deallocate the serial port */
	      FreeMiscResource(MR_SERIALPORT);
	      abort();
	    }
	}
      else
	{
	  printf("\nSerial port in use by %s\n",owner);
	  abort();
	}
      
    }
}

void GetOut()
{
  if (GotPort)
    {
      FreeMiscResource(MR_SERIALPORT);
      FreeMiscResource(MR_SERIALBITS);
    }
}

void  send(UBYTE b)
{
  UBYTE bits;
#ifdef DBG
    printf("C: %2x\n",b);
#endif  
  timereset();
  for (bits=1;bits<=8;bits++)
    {
      if (b&1) 
	setport(2);
      else
	setport(1);
      while(getport() != 0) timetest();
      timereset();
      setport(3);
      while (getport() !=3) timetest();
      b>>=1;
      SlowDown();
    }
}

/* Sends a byte to the TI85 */
UBYTE recv(void)         
{
  UBYTE curbit=1;
  UBYTE byt=0,bits,x;
  
  timereset();
  for(bits=1; bits<=8;bits++)
    {
      while((x=getport()) == 3) timetest();;
#ifdef DEBUG
	  printf("recv: Waiting for bit\n");
#endif
      if (x==1)
	{
#ifdef DEBUG
	      printf("recv: Received a 1\n");
#endif
	      byt += curbit;
	      setport(1);
	      x=2;
	    }
	  else
	    {
#ifdef DEBUG
	      printf("recv: Received 0\n");
#endif
	      setport(2);
	      x=1;
	    }
      timereset();
      while ((getport() & x) == 0) timetest();
      setport(3);
      curbit <<=1;
      SlowDown();
    }
#ifdef DBG
  printf("T: %2x\n",byt);
#endif
  return byt;
}
  

