//#define DEBUG
//#define STAT




#include <stdio.h>
#include <stdlib.h>

/* Amiga */
/* Hardware : */
#include <exec/types.h>
#include <hardware/cia.h>

/* System : */
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <devices/serial.h>
#include <proto/dos.h>
#include <proto/exec.h>

#include "hard.h"

/* low bit in ciaptr means high potential */
#define HIGH  0
#define LOW   1

inline void   ti_setbit(int value, UBYTE where);
inline UBYTE  ti_getbit(UBYTE where);


extern struct CIA ciaa, ciab;
struct MsgPort  *SerialMP=NULL;     /* Message port pointer */
struct IOExtSer *SerialIO=NULL;    /* I/O request pointer */

static int state=0;
#define STATE_PORT  1
#define STATE_EXTIO 2
#define STATE_DEV   4




#include "timer.h"
Timer_Info time_info;


#define HARD_MAX_TRY_ACTIVE     100
#define HARD_MAX_TRY            (HARD_MAX_TRY_ACTIVE+30)

/* Wait after setting : */
#define WAIT_SET timer_delay(&time_info,10)
//#define WAIT_SET printf("coucou\n");

/* Wait after retrying : */
#define WAIT_RETR timer_delay(&time_info,1000)
//#define WAIT_RETR printf("coucou2\n");

/* Wait if a timeout occures : */
#define WAIT_TIMEOUT timer_delay(&time_info,50000)
//#define WAIT_TIMEOUT printf("bouh\n");



extern int debug_mode;

int ti_openport(void )
{
  if ( ! debug_mode )
  {
  if (  !( SerialMP=CreatePort(NULL,0)) )
  {
    printf(__FILE__"> CreatePort failed.\n");
    ti_closeport();
    return(1);
  }
  state += STATE_PORT;

  if ( !( SerialIO=(struct IOExtSer *)CreateExtIO(SerialMP,sizeof(struct IOExtSer)) ) )
  {
    printf(__FILE__"> Unable to open SerialIO.\n");
    ti_closeport();
    return(1);
  }
  state += STATE_EXTIO;

  if ( OpenDevice(SERIALNAME,0L,(struct IORequest *)SerialIO,0))
  {
    printf(__FILE__"> Unable to open serial port ( %s unit 0 )\n",SERIALNAME);
    ti_closeport();
    return(1);
  }
  state += STATE_DEV;
  }
  /* We now have the serial device for ourselves */
  ti_initport();


  if ( timer_create(&time_info) )
  {
    printf(__FILE__"> Error creating timer\n");
    ti_closeport();
    return(1);
  }


  ciaa.ciaddrb = 0xc0;


  return(0); /* No error */
}

void ti_closeport(void )
{
  ti_initport();
  if ( ! debug_mode )
  {
    if ( state & STATE_DEV )
      CloseDevice((struct IORequest *)SerialIO);

    if ( state & STATE_EXTIO )
      DeleteExtIO((struct IORequest *)SerialIO);
    if ( state & STATE_PORT )
      DeletePort(SerialMP);
  }
  timer_delete(&time_info);
  state = 0;
}


inline void ti_setbit(int value, UBYTE where)
{
  if ( value )
    ciab.ciapra=ciab.ciapra|where;
  else
    ciab.ciapra=ciab.ciapra&(where^0xFF);
}



inline UBYTE ti_getbit(UBYTE where)
{
  if ( ciab.ciapra&where )
    return(1);
  else
    return(0);
}


inline void ti_initport(void )
{
  ti_setbit(HIGH,CIAF_COMDTR);
  ti_setbit(HIGH,CIAF_COMRTS);
}


inline int ti_sendbit(UBYTE bit )
{
  int where1, where2;
  unsigned long int count=0;

  if ( bit )
  {
    where1 = CIAF_COMDTR;
    where2 = CIAF_COMCTS;
  }
  else
  {
    where1 = CIAF_COMRTS;
    where2 = CIAF_COMDSR;
  }

  ti_setbit(LOW,where1);

  while ( ti_getbit(where2) != LOW && count <= HARD_MAX_TRY )
  {
    if ( count >= HARD_MAX_TRY_ACTIVE )
      WAIT_RETR;

    count++;
  }
  if ( count > HARD_MAX_TRY )
  {
#ifdef DEBUG
		printf(__FILE__"> sendbit Timeout send 1 (%ld)\n",count);
#endif
    WAIT_TIMEOUT;
    return(HARD_TIMEOUT);
  }

#ifdef STAT
  printf(__FILE__"> sendbit Acquittement recu , count=%ld\n",count);
#endif
  ti_setbit(HIGH,where1);

  count = 0;
  while ( ti_getbit(where2) != HIGH && count <= HARD_MAX_TRY )
  {
    if ( count >= HARD_MAX_TRY_ACTIVE )
      WAIT_RETR;
    count++;
  }
#ifdef STAT
  printf(__FILE__"> sendbit Fin acquittement recu , count=%ld\n",count);
#endif

  if ( count > HARD_MAX_TRY )
  {
#ifdef DEBUG
    printf(__FILE__"> sendbit Timeout send 2 (%ld)\n",count);
#endif
    WAIT_TIMEOUT;
    return(HARD_TIMEOUT);
  }

  return(0);
}

inline int ti_recvbit(UBYTE *result )
{
  unsigned long int count,count2;

  count2 = 0;

  do
  {
    if ( ti_getbit(CIAF_COMCTS) == LOW )
    {
#ifdef STAT
			printf(__FILE__"> recvbit CTS==LOW count=%ld\n",count2);
#endif
      ti_setbit(LOW,CIAF_COMDTR);


      count=0;
      while ( ti_getbit(CIAF_COMCTS) == LOW && count <= HARD_MAX_TRY )
      {
        if ( count >= HARD_MAX_TRY_ACTIVE )
          WAIT_RETR;
        count++;
      }

      ti_setbit(HIGH,CIAF_COMDTR);
			
			
			WAIT_SET;
			/*for ( count=0; count<30000; count++);*/


#ifdef STAT
			//puts(__FILE__"> recvbit result=0\n");
#endif


      *result = 0;

      if ( count > HARD_MAX_TRY )
      {
#ifdef DEBUG
        printf(__FILE__"> Timeout recv A (%ld)\n",count);
#endif
        WAIT_TIMEOUT;
        return(HARD_TIMEOUT);
      }

      return(0);
    }

    if ( ti_getbit(CIAF_COMDSR) == LOW )
    {
#ifdef STAT
			printf(__FILE__"> recvbit DSR==LOW count=%ld\n",count2);
#endif
      ti_setbit(LOW,CIAF_COMRTS);


      count=0;
      while ( ti_getbit(CIAF_COMDSR) == LOW && count <= HARD_MAX_TRY )
      {
        if ( count >= HARD_MAX_TRY_ACTIVE )
          WAIT_RETR;
        count++;
      }

      ti_setbit(HIGH,CIAF_COMRTS);

      WAIT_SET;
#ifdef STAT
			printf(__FILE__"> recvbit result=1, count=%ld\n",count);
#endif

      *result = 1;


      if ( count > HARD_MAX_TRY )
      {
#ifdef DEBUG
        printf(__FILE__"> rB%ld\n",count);
        printf(__FILE__"> Timeout recv B (%ld)\n",count);
#endif
        WAIT_TIMEOUT;
        return(HARD_TIMEOUT);
      }

      return(0);
    }
    if ( count2 >= HARD_MAX_TRY_ACTIVE )
      WAIT_RETR;
    count2++;
  }
  while(count2<HARD_MAX_TRY);

#ifdef DEBUG
  printf(__FILE__"> Timeout recv C (%ld)\n",count2);
#endif
  ti_initport();
  WAIT_TIMEOUT;
  return(HARD_TIMEOUT);
}


