
/* Comm serial I/O handlers */

extern struct IOExtSer *AllocMem();
extern struct MenuItem BaudItems[];
extern UBYTE  doinit[], doexit[];

static   int   bits, length, parity;
static   int   xbits, xlength, xparity;

#define  SERIALIO 1
#include "globals.h"

init_serial()
{
    Read_Request = AllocMem((long)sizeof(*Read_Request),
                                  MEMF_PUBLIC | MEMF_CLEAR);
    Read_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
    Read_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Read_RS",0L);

    if(OpenDevice(SERIALNAME,0L,Read_Request,0L))
       return FALSE;

    Read_Request->IOSer.io_Command = CMD_READ;
    Read_Request->IOSer.io_Length  = 1;
    Read_Request->IOSer.io_Data    = (APTR) &rs_in[0];

    Write_Request = AllocMem((long)sizeof(*Write_Request),
                                   MEMF_PUBLIC | MEMF_CLEAR);
    Write_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
    Write_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Write_RS",0L);

    if(OpenDevice(SERIALNAME,0L,Write_Request,0L))
      return FALSE;

    Echo_Request = AllocMem((long)sizeof(*Echo_Request),
                        MEMF_PUBLIC | MEMF_CLEAR);
    Echo_Request->io_SerFlags = SERF_XDISABLED | SERF_SHARED | IOF_QUICK;
    Echo_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Echo_RS",0L);

    if(OpenDevice(SERIALNAME,0L,Echo_Request,0L))
      return FALSE;

    Write_Request->IOSer.io_Command = CMD_WRITE;
    Write_Request->IOSer.io_Length  = 1;
    Write_Request->IOSer.io_Data    = (APTR) &rs_out[0];

    Echo_Request->IOSer.io_Command  = CMD_WRITE;
    Echo_Request->IOSer.io_Length   = 1;
    Echo_Request->IOSer.io_Data     = (APTR) &rs_echo[0];

    Read_Request->io_SerFlags       = SERF_SHARED | SERF_XDISABLED;
    Read_Request->IOSer.io_Length   = 1;
    Read_Request->IOSer.io_Data     = (APTR) &rs_in[0];
    Read_Request->io_Baud           = baud;
    Read_Request->io_ReadLen        = 8;
    Read_Request->io_WriteLen       = 8;
    Read_Request->io_CtlChar        = 0x11130000L;
    Read_Request->io_RBufLen        = 1024;
    Read_Request->IOSer.io_Command  = SDCMD_SETPARAMS;

    DoIO(Read_Request);
    Read_Request->IOSer.io_Command  = CMD_READ;

    return TRUE;
}
/**************************************************************/
/* send char and read char functions for the xmodem function */
/************************************************************/
sendchar(ch)
int ch;
{
   rs_out[0] = ch & 0xFF;
   DoIO(Write_Request);
}


/************************/
/* echo char to sender  */
/************************/
echochar(ch)
int ch;
{
   rs_echo[0] = ch & 0xFF;
   DoIO(Echo_Request);
   if(ch == '\r')
     echochar('\n');
}


/*************************************
readchar() waits for a character
  timeout built in.
  Timeout condition causes error return
  'seconds' controls duration of wait.
  'doabort' TRUE indicates that CAN recvd
     will set cancel flag
**************************************/
readchar( seconds, doabort )
unsigned int doabort, seconds;
{
   extern void emits_rx();
   extern long CheckIO();

   UBYTE ch;

   timeout = FALSE;
   StartTimer((unsigned long)seconds,0L);      /* start timeout */

/* wait for a TX window event, the timer to timeout or for a receive character */
wait:
   Wait(  1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit
        | 1L << TimerMsgPort.mp_SigBit
        | 1L << tx_window->UserPort->mp_SigBit );

   if(CheckIO(Read_Request))     /* if IO request has completed */
    {
       AbortIO(&TimerIO);
       Wait( 1L << TimerMsgPort.mp_SigBit);
       WaitIO(Read_Request);     /* remove the message from the queue */
       ch = rs_in[0];            /* get character */
       BeginIO(Read_Request);    /* start a new request */
       if( ch == CAN && doabort) /* if this is a CAN char and doabort TRUE */
            cancel = TRUE;       /* set cancel flag */
       return (int)(ch);
    }
/* see if the timer timed out */
  if(CheckIO(&TimerIO))          /* was timeout */
  {
    emits_rx("  Timeout\n");
    timeout = TRUE;
    return TIMEOUT;
  }
/* otherwise it was a tx_window input */
  Process_window_event();
  if(abort)
  {
    AbortIO(&TimerIO);
    Wait( 1L << TimerMsgPort.mp_SigBit);
    return TIMEOUT;
  }
  goto wait;                     /* wait for Timeout or character */
}

/***********************************
  Flush receive buffer.
  Removes pending rx characters to
  help maintain line syncronization
************************************/  
void purge_line()
{
   purge_port();
   BeginIO(Read_Request);
}

purge_port()
{
   AbortIO(Read_Request);                 /* abort any reads */
   WaitIO(Read_Request);                  /* wait for abort to complete */

   Read_Request->IOSer.io_Command = CMD_FLUSH;
   DoIO(Read_Request);                       /* flush all IO requests */

   Read_Request->IOSer.io_Command = CMD_CLEAR;
   DoIO(Read_Request);                       /* flush receive buffer  */

   Read_Request->IOSer.io_Command = CMD_READ;
}

/* enable/disable XON/XOFF checking in the serial driver */
Xon(val)
int val;
{
   AbortIO(Read_Request);
   WaitIO(Read_Request);

   if(val)        /* if TRUE, turn on XON/XOFF handling */
      Read_Request->io_SerFlags &= ~SERF_XDISABLED;
   else           /* disable XON/XOFF */
      Read_Request->io_SerFlags |= SERF_XDISABLED;

    Read_Request->IOSer.io_Command  = SDCMD_SETPARAMS;
    DoIO(Read_Request);

    Read_Request->IOSer.io_Command  = CMD_READ;
    BeginIO(Read_Request);
}

/*  Close the serial device */
Close_Serial()
{
  if( Read_Request )          /* if open, close it */
   {
     CloseDevice( Read_Request );
     DeletePort( Read_Request->IOSer.io_Message.mn_ReplyPort );
     FreeMem( Read_Request, (long)sizeof(*Read_Request) );
   }
  if( Write_Request )         /* ditto */
   {
     CloseDevice( Write_Request );
     DeletePort( Write_Request->IOSer.io_Message.mn_ReplyPort );
     FreeMem( Write_Request, (long)sizeof(*Write_Request) );
   }
  if( Echo_Request )          /* ditto */
   {
     CloseDevice( Echo_Request );
     DeletePort( Echo_Request->IOSer.io_Message.mn_ReplyPort );
     FreeMem( Echo_Request, (long)sizeof(*Echo_Request) );
   }
}


/***********************************
  Start line.
  Restart line if stopped with XOFF
************************************/  
void Start_line()
{
   sendchar(XON);
 /* use Echo_Request because it's not busy at the time this is called */
   Echo_Request->IOSer.io_Command = CMD_START;
   DoIO(Echo_Request);                       /* Restart line request */
}

/***********************************
Set baud rate
***********************************/
void set_baud( num )
int num;
{
   USHORT i,itemnum;

   switch( num )
   {
      case 300:  itemnum = 0; break;
      case 1200: itemnum = 1; break;
      case 2400: itemnum = 2; break;
      case 4800: itemnum = 3; break;
      case 9600: itemnum = 4; break;
      case 19200:itemnum = 5; break;
      default: return;
   }
   baud = num;

   purge_port();
   Read_Request->io_Baud = (long)num;  /* set new baud rate */
   Setparams();

   for(i = 0; i < RSMAX; i++)
      BaudItems[ i ].Flags       &= ~CHECKED;  /* reset Checkmark */
      BaudItems[ itemnum ].Flags |= CHECKED;   /* Check real baud rate */
}

/* see if any characters are in the receive buffer */
/* return FALSE if IO pending, TRUE if not */
check_line()
{
   return(CheckIO(Read_Request));
}

/* Read the characters buffered in the RX buffer.
   First satisfy the 1 character read we started.
   Then do an I/O query to see how many more characters are ready.
   Then issue a Read request for these characters.
*/
USHORT Read_RS()
{
   USHORT len;

   WaitIO(Read_Request);      /* read the 1st rx character */

   Echo_Request->IOSer.io_Command = SDCMD_QUERY;
   DoIO(Echo_Request);

   dcd = Echo_Request->io_Status & 0x28;
   len = Echo_Request->IOSer.io_Actual;  /* how many bytes in RX buffer */

   if(len != 0)
   {
      if(len > RSBUFSIZ-1)          /* lets not overflow our buffer */
         len = RSBUFSIZ-1;
      Read_Request->IOSer.io_Length = len;
      Read_Request->IOSer.io_Data    = (APTR) &rs_in[1];
      DoIO(Read_Request);           /* go get em */
      Read_Request->IOSer.io_Length = 1;
      Read_Request->IOSer.io_Data    = (APTR) &rs_in[0];
   }
   return (len + 1);
}


SendBreak()
{
 /* use Echo_Request because it's not busy at the time this is called */
   Echo_Request->IOSer.io_Command  = SDCMD_BREAK;
   Echo_Request->io_SerFlags      |= SERF_QUEUEDBRK;
   DoIO(Echo_Request);                       /* Restart line request */
   Echo_Request->io_SerFlags      &= ~SERF_QUEUEDBRK;
}

Setparity(parnum)
int parnum;
{
  WaitRequest();
  switch( parnum )
  {
     case 0:            /* no parity */
              Read_Request->io_SerFlags &= ~SERF_PARTY_ON;
              break;
     case 1:            /* odd parity */
              Read_Request->io_SerFlags |= SERF_PARTY_ODD | SERF_PARTY_ON;
              break;
     case 2:            /* even parity */
              Read_Request->io_SerFlags |= SERF_PARTY_ON;
              Read_Request->io_SerFlags &= ~SERF_PARTY_ODD;
              break;
  }
  parity = parnum;
  Setparams();
}

Setlength( len )
int len;
{
    WaitRequest();
    switch( len )
    {
       case 0:            /* 8 bits */
                 Read_Request->io_ReadLen =
                 Read_Request->io_WriteLen = 8;
                 break;
       case 1:            /* 7 bits */
                 Read_Request->io_ReadLen =
                 Read_Request->io_WriteLen = 7;
                 break;
    }
    length = len;
    Setparams();
}

Setstopbits( num )
int num;
{
   if( (Read_Request->io_ReadLen == 8) & ( num == 1 ) )
   {
      emits_rx("SERIAL DEVICE ERROR: can't have 2 stop bits with 8 bit word\n");
      return;
   }

   WaitRequest();
   switch( num )
   {
      case 0:            /* 1 stop bit */
                Read_Request->io_StopBits = 1;
                break;
      case 1:            /* 2 stop bits */
                Read_Request->io_StopBits = 2;
                break;
   }
   bits = num;
   Setparams();
}

Setparams()
{
   Read_Request->IOSer.io_Command = SDCMD_SETPARAMS;
   DoIO(Read_Request);
   Read_Request->IOSer.io_Command = CMD_READ;
   BeginIO(Read_Request);
}

WaitRequest()
{
   AbortIO(Read_Request);                  /* abort it */
   WaitIO(Read_Request);                   /* wait for abort to finish */
}

Xconfig( state )
int state;
{
   if(state == FALSE)          /* restore state */
   {
      Setstopbits( xbits );
      Setparity( xparity );
      Setlength( xlength );
      Xon(xonflg);
   }
   else
   {
      xbits = bits; xparity = parity ; xlength = length;
      Setstopbits( 0 );    /* 1 stop bit */
      Setparity( 0 );      /* no parity */
      Setlength( 0 );      /* 8 bits */
      Xon( FALSE );
   }
}

Modem_init()
{
   sendout(doinit);
}

Modem_exit()
{
   sendout(doexit);
}

