/****h* TimeSerial.c ****************************************************
*
* NAME
*    TimedSerial.c
*
* DESCRIPTION
*    This file contains the code to issue serial commands
*    that will time-out if there is no response from the
*    PC at the other end of the serial link.
*
* HISTORY
*    28-Sep-2000 - Added the serName parameter to the OpenSerial()
*                  function. 
*    30-Dec-1998 - Added GetErrNum() & GetSerialStatus();
*    06-Nov-1996 - Created.
*
* WARNINGS
*    These functions have NOT been tested thoroughly, but they
*    are guaranteed to time out, so your system won't freeze if
*    you use them!
*
* NOTES
*    The following functions are available to the User:
*
*    VISIBLE int   GetErrNum( void );
*    VISIBLE int   GetSerialStatus( void );
*    VISIBLE void  TimerDelay( int delayseconds );
*    VISIBLE int   TestTimer( void );
*    VISIBLE char *TranslateErrorNumber( int errnum );
*
*    VISIBLE int   OpenSerial( char *serName,
*                              int   unit, 
*                              int   HowLong, 
*                              int   buffersize,
*                              int   flags
*                            ); 
*
*    VISIBLE void  CloseSerial( void );
*
*    VISIBLE char  *ReadString( int timeout, int strsize );
*    VISIBLE UBYTE  ReadChar(   int timeout              );
*
*    VISIBLE int WriteString( int timeout, char *string, int strsize );
*    VISIBLE int WriteChar(   int timeout, int   ch                  );
*
*    VISIBLE int ResetSerial( int timeout );
*    VISIBLE int ClearSerial( int timeout );
*    VISIBLE int FlushSerial( int timeout );
*    VISIBLE int StopSerial(  int timeout );
*    VISIBLE int StartSerial( int timeout );
*    VISIBLE int QuerySerial( int timeout );
*
*    VISIBLE int BreakSerial( int timeout, int duration );
*    VISIBLE int SetSerialParams( int timeout, int which, int params );
*
* $VER: TimedSerial.c 1.1 (28-Sep-2000) by J.T. Steichen
************************************************************************
*
*/

#include <stdio.h>
#include <string.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/io.h>

#include <devices/timer.h>
#include <devices/serial.h>

#include <dos/dos.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

#ifndef  PRIVATE         // storage types to increase readability.
# define PRIVATE static  
# define IMPORT  extern
# define PUBLIC
# define VISIBLE
#endif

#define    ALLOCATE       1
# include "TimedSerial.h"
#undef     ALLOCATE

// -------------------------------------------------------------------

IMPORT struct MsgPort *CreatePort( char *, ULONG );

IMPORT void DeletePort( struct MsgPort * );

// -------------------------------------------------------------------

PRIVATE int                 ErrorNumber = 0;

PRIVATE struct timerequest *SerTimer    = NULL;
PRIVATE struct MsgPort     *TimerPort   = NULL;

// -------------------------------------------------------------------

/****h* GetErrNum() ****************************************************
*
* NAME
*    GetErrNum()
*
* SYNOPSIS
*    int errnum = GetErrNum( void );
*
* DESCRIPTION
*    Return the value that the internal ErrorNumber variable is set at.
************************************************************************
*
*/

PUBLIC int GetErrNum( void ) { return( ErrorNumber ); }

/****i* SetupTimer() ***************************************************
*
* NAME
*    SetupTimer()
*
* DESCRIPTION
*    Initialize the timer's Port & Open the device.
************************************************************************
*
*/

PRIVATE int SetupTimer( int HowLong )
{
   if ((TimerPort = (struct MsgPort *) 
                    CreatePort( "serial.timer", 0 )) == NULL)
      return( -1 );

   if ((SerTimer = (struct timerequest *) 
                   AllocVec( sizeof( struct timerequest ), 
                             MEMF_CLEAR | MEMF_ANY )) == NULL)
      {
      DeletePort( TimerPort );

      return( -2 );
      }

   SerTimer->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
   SerTimer->tr_node.io_Message.mn_Node.ln_Pri  = 0;
   SerTimer->tr_node.io_Message.mn_ReplyPort    = TimerPort;

   if (OpenDevice( TIMERNAME, UNIT_VBLANK, 
                   (struct IORequest *) SerTimer, 0 ) != 0)
      {
      FreeVec( SerTimer );
      DeletePort( TimerPort );

      return( -3 );
      }

   TimeValue = HowLong;
   return 0;
}

/****i* CloseTimer() *************************************************
*
* NAME
*    CloseTimer()
*
* DESCRIPTION
*    Close the Timer & Serial devices & Free memory allocated.  
**********************************************************************
*
*/

PRIVATE void CloseTimer( void )
{
   CloseDevice( (struct IORequest *) SerTimer );
   DeletePort( SerTimer->tr_node.io_Message.mn_ReplyPort );

   SerTimer->tr_node.io_Message.mn_Node.ln_Type = 0xFF;
   SerTimer->tr_node.io_Device                  = (struct Device *) NULL;
   SerTimer->tr_node.io_Unit                    = (struct Unit *) NULL;

   FreeVec( SerTimer );

   SerTimer  = NULL;
   TimerPort = NULL;
   TimeValue = 0;
   return;
}

/****i* StartTimer() ************************************************
*
* NAME
*    StartTimer()
*
* DESCRIPTION
*    Tell the timeout timer to begin timing the serial device.
*********************************************************************
*
*/

PRIVATE void StartTimer( int interval )
{
   TimedOut                     = FALSE;
   TimeValue                    = interval;

   SerTimer->tr_time.tv_secs    = interval;
   SerTimer->tr_time.tv_micro   = 0;
   SerTimer->tr_node.io_Command = TR_ADDREQUEST;

   SendIO( (struct IORequest *) SerTimer );

   return;
}

/****i* KillTimer() *************************************************
*
* NAME
*    KillTimer()
*
* DESCRIPTION
*    Stop the Serial timeout timer 
*
* NOTES
*    CloseTimer() still has to be called in order to shut down
*    completely!
*********************************************************************
*
*/

PRIVATE void KillTimer( void )
{
   AbortIO( (struct IORequest *) SerTimer );

   (void) GetMsg( SerTimer->tr_node.io_Message.mn_ReplyPort );

   return;
}

/****h* TimerDelay() ************************************************
*
* NAME
*    TimerDelay()
*
* DESCRIPTION
*    Start the Serial timeout timer & wait for it to time-out.
*********************************************************************
*
*/

VISIBLE void TimerDelay( int delayseconds )
{
   StartTimer( delayseconds );

   Wait( 1L << SerTimer->tr_node.io_Message.mn_ReplyPort->mp_SigBit );

   (void) GetMsg( SerTimer->tr_node.io_Message.mn_ReplyPort );

   return;
}

/****h* TestTimer() *************************************************
*
* NAME
*    TestTimer()
*
* DESCRIPTION
*    Return any timer error values (zero means NO ERROR).
*********************************************************************
*
*/

VISIBLE int TestTimer( void )
{
   return( CheckIO( (struct IORequest *) SerTimer ) 
           && ( !SerTimer->tr_node.io_Error) );
}

/****h* TranslateErrorNumber() **************************************
*
* NAME
*    TranslateErrorNumber()
*
* DESCRIPTION
*    Return a string corresponding to the given error number.
*********************************************************************
*
*/

PRIVATE char *SerErrors[] = {

   "No serial error.",    
   "Device is Busy.",
   "Baud rate NOT supported by hardware.",
   "Unknown error number.",
   "Failed to allocate new read buffer.",
   "Bad parameter.",
   "Hardware data overrun!",
   "Unknown error number.",
   "Unknown error number.",
   "Parity ERROR.",
   "Unknown error number.",
   "Timeout (if using 7-wire handshaking).",
   "Read buffer overflowed.",
   "No Data Set ready.",
   "Unknown error number.",
   "Break detected.",
   "Selected unit already in use.",
   NULL
};

VISIBLE char *TranslateErrorNumber( int errnum )
{
   if (errnum < 17 && errnum >= 0 )
      return( SerErrors[ errnum ] );
   else
      return( "Bad Error Number!" );
}

/****h* OpenSerial() ************************************************
*
* NAME
*    OpenSerial()
*
* SYNOPSIS
*    int success = OpenSerial( char *serName,    // Name of Serial device
*                              int   unit,       // Serial Unit #
*                              int   HowLong,    // Timeout delay
*                              int   buffersize, // Serial buffer size
*                              int   flags       // SerialIO Flags
*                            );
*
* DESCRIPTION
*    Initialize & Open the Serial & timer devices.
*********************************************************************
*
*/

VISIBLE int OpenSerial( char *sername, 
                        int   unit, 
                        int   HowLong, 
                        int   buffersize, 
                        int   flags
                      ) 
{
   ULONG    readbit, writebit, timebit;
   
   if ((ReadRequest = (struct IOExtSer *) 
                      AllocVec( sizeof( struct IOExtSer ), 
                                MEMF_CLEAR | MEMF_PUBLIC )) == NULL)   
      return( -1 );
      
   if ((ReadBuffer = (char *) AllocVec( buffersize, MEMF_CLEAR )) == NULL)
      {
      FreeVec( ReadRequest );

      return( -2 );
      }

   ReadSize                 = buffersize;
   ReadRequest->io_SerFlags = flags; // SERF_SHARED | SERF_XDISABLED;

   if ((ReadRequest->IOSer.io_Message.mn_ReplyPort = CreatePort( 
                          "serial.read", 0 )) == NULL)
      {
      FreeVec( ReadBuffer  );
      FreeVec( ReadRequest );

      return( -3 );
      }

   if (sername == NULL)
      {
      if (OpenDevice( SERIALNAME, unit, (struct IORequest *) ReadRequest, 
                      0 ) != 0)
         {
         DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );
         
         FreeVec( ReadBuffer  );
         FreeVec( ReadRequest );
      
         return( -4 );
         }
      }
   else
      {
      if (OpenDevice( sername, unit, (struct IORequest *) ReadRequest, 
                      0 ) != 0)
         {
         DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );
         
         FreeVec( ReadBuffer  );
         FreeVec( ReadRequest );
      
         return( -4 );
         }
      }

   ReadRequest->IOSer.io_Command = CMD_READ;
   ReadRequest->IOSer.io_Length  = buffersize;
   ReadRequest->IOSer.io_Data    = (APTR) ReadBuffer;
   
   if ((WriteRequest = (struct IOExtSer *) 
                       AllocVec( sizeof( struct IOExtSer ), 
                                 MEMF_CLEAR | MEMF_PUBLIC )) == NULL)   
      {
      CloseDevice( (struct IORequest *) ReadRequest ); 
      DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );

      FreeVec( ReadBuffer  );
      FreeVec( ReadRequest );

      return( -5 );
      }
      
   if ((WriteBuffer = (char *) AllocVec( buffersize, MEMF_CLEAR )) == NULL)
      {
      FreeVec( WriteRequest );
      
      CloseDevice( (struct IORequest *) ReadRequest ); 
      DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );
      
      FreeVec( ReadBuffer  );
      FreeVec( ReadRequest );
      
      return( -6 );
      }

   WriteSize                 = buffersize;
   WriteRequest->io_SerFlags = flags; // SERF_SHARED | SERF_XDISABLED;

   if ((WriteRequest->IOSer.io_Message.mn_ReplyPort = CreatePort( 
                          "serial.write", 0 )) == NULL)
      {
      FreeVec( WriteBuffer  );
      FreeVec( WriteRequest );

      CloseDevice( (struct IORequest *) ReadRequest ); 
      DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );

      FreeVec( ReadBuffer  );
      FreeVec( ReadRequest );

      return( -7 );
      }

   if (sername == NULL)
      {
      if (OpenDevice( SERIALNAME, unit, (struct IORequest *) WriteRequest, 
                      0 ) != 0)
         {
         DeletePort( WriteRequest->IOSer.io_Message.mn_ReplyPort );

         FreeVec( WriteBuffer  );
         FreeVec( WriteRequest );

         CloseDevice( (struct IORequest *) ReadRequest ); 
         DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );

         FreeVec( ReadBuffer  );
         FreeVec( ReadRequest );

         return( -8 );
         }
      }
   else
      {
      if (OpenDevice( sername, unit, (struct IORequest *) WriteRequest, 
                      0 ) != 0)
         {
         DeletePort( WriteRequest->IOSer.io_Message.mn_ReplyPort );

         FreeVec( WriteBuffer  );
         FreeVec( WriteRequest );

         CloseDevice( (struct IORequest *) ReadRequest ); 
         DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );

         FreeVec( ReadBuffer  );
         FreeVec( ReadRequest );

         return( -8 );
         }
      }

   WriteRequest->IOSer.io_Command = CMD_WRITE;
   WriteRequest->IOSer.io_Length  = ReadSize;
   WriteRequest->IOSer.io_Data    = (APTR) WriteBuffer;

   ReadRequest->io_SerFlags      = SERF_SHARED | SERF_XDISABLED;
   ReadRequest->io_Baud          = 9600;
   ReadRequest->io_ReadLen       = 8;
   ReadRequest->io_WriteLen      = 8;
   ReadRequest->io_RBufLen       = ReadSize;
   ReadRequest->io_CtlChar       = 1L;
   ReadRequest->IOSer.io_Command = SDCMD_SETPARAMS;

   DoIO( (struct IORequest *) ReadRequest );

   ReadRequest->IOSer.io_Command = CMD_READ;
   ErrorNumber                   = ReadRequest->IOSer.io_Error;

   readbit  = 1L << ReadRequest->IOSer.io_Message.mn_ReplyPort->mp_SigBit;
   writebit = 1L << WriteRequest->IOSer.io_Message.mn_ReplyPort->mp_SigBit;

   if (SetupTimer( HowLong ) < 0)
      {
      CloseDevice( (struct IORequest *) WriteRequest ); 
      DeletePort( WriteRequest->IOSer.io_Message.mn_ReplyPort );

      FreeVec( WriteBuffer  );
      FreeVec( WriteRequest );

      CloseDevice( (struct IORequest *) ReadRequest ); 
      DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );

      FreeVec( ReadBuffer  );
      FreeVec( ReadRequest );

      return( -9 );
      }

   timebit = 1L << SerTimer->tr_node.io_Message.mn_ReplyPort->mp_SigBit;

   WaitSerMask = SIGBREAKF_CTRL_C | readbit | writebit | timebit;

   return( 0 ); 
}

/****h* CloseSerial() ***********************************************
*
* NAME
*    CloseSerial()
*
* SYNOPSIS
*    void CLoseSerial( void );
*
* DESCRIPTION
*    Close the Serial & timeout timer devices, then Free the memory
*    allocated to them.
*********************************************************************
*
*/

VISIBLE void CloseSerial( void )
{
   KillTimer();
   CloseTimer();

   CloseDevice( (struct IORequest *) WriteRequest ); 
   DeletePort( WriteRequest->IOSer.io_Message.mn_ReplyPort );

   FreeVec( WriteBuffer  );
   FreeVec( WriteRequest );

   CloseDevice( (struct IORequest *) ReadRequest ); 
   DeletePort( ReadRequest->IOSer.io_Message.mn_ReplyPort );

   FreeVec( ReadBuffer  );
   FreeVec( ReadRequest );

   return;
}

/****h* ReadString() *********************************************
*
* NAME
*    ReadString()
*
* SYNOPSIS
*    char *string = ReadString( int timeout, int strsize );
*
* DESCRIPTION
*    Read a string strsize characters long from the Serial port.
*    NULL will be returned if the timer times out or if there's
*    an error.
******************************************************************
*
*/

VISIBLE char *ReadString( int timeout, int strsize )
{
   ULONG temp = 0L;

   KillTimer();   

   if (strsize > ReadSize)
      {
      FreeVec( ReadBuffer );

      ReadBuffer = (char *) AllocVec( strsize, MEMF_CLEAR );

      if (ReadBuffer == NULL)
         {
         fprintf( stderr, "Ran out of memory!\n" );

         return( NULL );
         }

      ReadSize = strsize;
      }

   TimeValue = timeout;
   StartTimer( timeout );

   ReadRequest->IOSer.io_Command = CMD_READ;
   ReadRequest->IOSer.io_Length  = strsize;
   ReadRequest->IOSer.io_Data    = (APTR) ReadBuffer;

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;

         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;
         WaitIO( (struct IORequest *) ReadRequest );

         return( ReadBuffer );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;

         return( NULL );
         }
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO( (struct IORequest *) ReadRequest );

   ErrorNumber = ReadRequest->IOSer.io_Error;

   return( ReadBuffer );
}

/****h* ReadChar() ***********************************************
*
* NAME
*    ReadChar()
*
* SYNOPSIS
*    UBYTE ch = ReadChar( int timeout );
*
* DESCRIPTION
*    Read a single character from the Serial port.
******************************************************************
*
*/

VISIBLE UBYTE ReadChar( int timeout )
{
   UBYTE *rt = NULL, rval = 0;
   
   rt   = ReadString( timeout, 1 );
   rval = *rt;

   return( rval );
}

/****h* WriteString() ********************************************
*
* NAME
*    WriteString()
*
* SYNOPSIS
*    int success = WriteString( int   timeout, 
*                               char *string,
*                               int   strsize
*                             );
*
* DESCRIPTION
*    Write a string to the Serial Port (zero means success). 
******************************************************************
*
*/

VISIBLE int WriteString( int timeout, char *string, int strsize )
{
   ULONG temp = 0L;
   
   KillTimer();   

   if (strsize > WriteSize)
      {
      FreeVec( WriteBuffer );

      WriteBuffer = (char *) AllocVec( strsize, MEMF_CLEAR );

      if (WriteBuffer == NULL)
         {
         fprintf( stderr, "Ran out of memory!\n" );
         return( -1 );
         }

      WriteSize = strsize;
      }

   strncpy( WriteBuffer, string, strsize ); 

   TimeValue = timeout;
   StartTimer( timeout );

   WriteRequest->IOSer.io_Command = CMD_WRITE;
   WriteRequest->IOSer.io_Length  = strsize;
   WriteRequest->IOSer.io_Data    = (APTR) WriteBuffer;

   SendIO( (struct IORequest *) WriteRequest );

   ErrorNumber = WriteRequest->IOSer.io_Error;

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;
         break;
         }

      if (CheckIO( (struct IORequest *) WriteRequest ))
         {
         TimedOut = FALSE;
         WaitIO( (struct IORequest *) WriteRequest );
      
         ErrorNumber = WriteRequest->IOSer.io_Error;
         return( 0 );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;
         return( -2 );
         }
      }

   AbortIO( (struct IORequest *) WriteRequest );
   WaitIO( (struct IORequest *) WriteRequest );

   ErrorNumber = WriteRequest->IOSer.io_Error;

   return( -3 );
}

/****h* WriteChar() ************************************************
*
* NAME
*    WriteChar()
*
* SYNOPSIS
*    int success = WriteChar( int timeout, int ch );
*
* DESCRIPTION
*    Write a single character to the Serial Port 
*    (zero means success).
********************************************************************
*
*/

VISIBLE int WriteChar( int timeout, int ch )
{
   int rval = 0;
   
   *WriteBuffer       = (char) ch;
   *(WriteBuffer + 1) = '\0';
   
   rval = WriteString( timeout, WriteBuffer, 1 );

   return( rval );
}

/****h* ResetSerial() **********************************************
*
* NAME
*    ResetSerial()
*
* SYNOPSIS
*    int success = ResetSerial( int timeout );
*
* DESCRIPTION
*    Reset the Serial Port & change the timeout value.
*    (success >= 0 means NO ERROR).
********************************************************************
*
*/

VISIBLE int ResetSerial( int timeout )
{
   ULONG temp = 0L;
   
   KillTimer();   

   ReadRequest->IOSer.io_Command = CMD_RESET;

   TimeValue = timeout;

   StartTimer( timeout );

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;
         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;

         WaitIO( (struct IORequest *) ReadRequest );

         ErrorNumber = ReadRequest->IOSer.io_Error;
      
         return( (int) ReadRequest->IOSer.io_Actual );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;

         return( -1 );
         } 
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO( (struct IORequest *) ReadRequest );

   ErrorNumber = ReadRequest->IOSer.io_Error;

   return( (int) ReadRequest->IOSer.io_Actual );
}

/****h* ClearSerial() *********************************************
*
* NAME
*    ClearSerial()
*
* SYNOPSIS
*    int success = ClearSerial( int timeout );
*
* DESCRIPTION
*    Issue a CMD_CLEAR to the Serial device (success < 0 means
*    the timer timed out). 
*******************************************************************
*
*/

VISIBLE int ClearSerial( int timeout )
{
   ULONG temp = 0L;
   
   KillTimer();   

   ReadRequest->IOSer.io_Command = CMD_CLEAR;

   TimeValue = timeout;

   StartTimer( timeout );

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;
         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;

         WaitIO( (struct IORequest *) ReadRequest );
       
         ErrorNumber = ReadRequest->IOSer.io_Error;

         return( (int) ReadRequest->IOSer.io_Actual );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;
         return( -1 );
         } 
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO( (struct IORequest *) ReadRequest );

   ErrorNumber = ReadRequest->IOSer.io_Error;

   return( (int) ReadRequest->IOSer.io_Actual );
}

/****h* FlushSerial() *********************************************
*
* NAME
*    FlushSerial()
*
* SYNOPSIS
*    int success = FlushSerial( int timeout );
*
* DESCRIPTION
*    Issue a CMD_FLUSH to the Serial device (success < 0 means
*    the timer timed out). 
*******************************************************************
*
*/

VISIBLE int FlushSerial( int timeout )
{
   ULONG temp = 0L;
   
   KillTimer();   

   ReadRequest->IOSer.io_Command = CMD_FLUSH;

   TimeValue = timeout;

   StartTimer( timeout );

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;

         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;

         WaitIO( (struct IORequest *) ReadRequest );

         ErrorNumber = ReadRequest->IOSer.io_Error;

         return( (int) ReadRequest->IOSer.io_Actual );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;

         return( -1 );
         } 
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO(  (struct IORequest *) ReadRequest );

   ErrorNumber = ReadRequest->IOSer.io_Error;

   return( (int) ReadRequest->IOSer.io_Actual );
}

/****h* StopSerial() **********************************************
*
* NAME
*    StopSerial()
*
* SYNOPSIS
*    int success = StopSerial( int timeout );
*
* DESCRIPTION
*    Issue a CMD_STOP to the Serial device (success < 0 means
*    the timer timed out). 
*
* SEE ALSO
*    StartSerial()
*******************************************************************
*
*/

VISIBLE int StopSerial( int timeout )
{
   ULONG temp = 0L;
   
   KillTimer();   

   ReadRequest->IOSer.io_Command = CMD_STOP;

   TimeValue = timeout;

   StartTimer( timeout );

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;

         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;

         WaitIO( (struct IORequest *) ReadRequest );

         ErrorNumber = ReadRequest->IOSer.io_Error;

         return( (int) ReadRequest->IOSer.io_Actual );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;

         return( -1 );
         } 
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO(  (struct IORequest *) ReadRequest );

   ErrorNumber = ReadRequest->IOSer.io_Error;

   return( (int) ReadRequest->IOSer.io_Actual );
}

/****h* StartSerial() *********************************************
*
* NAME
*    StartSerial()
*
* SYNOPSIS
*    int success = StartSerial( int timeout );
*
* DESCRIPTION
*    Issue a CMD_START to the Serial device (success < 0 means
*    the timer timed out). 
*
* SEE ALSO
*    StopSerial()
*******************************************************************
*
*/

VISIBLE int StartSerial( int timeout )
{
   ULONG temp = 0L;
   
   KillTimer();   

   ReadRequest->IOSer.io_Command = CMD_START;

   TimeValue = timeout;

   StartTimer( timeout );

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;

         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;

         WaitIO( (struct IORequest *) ReadRequest );

         ErrorNumber = ReadRequest->IOSer.io_Error;

         return( (int) ReadRequest->IOSer.io_Actual );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;

         return( -1 );
         } 
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO( (struct IORequest *) ReadRequest );

   ErrorNumber = ReadRequest->IOSer.io_Error;

   return( (int) ReadRequest->IOSer.io_Actual );
}

/****h* BreakSerial() *********************************************
*
* NAME
*    BreakSerial()
*
* SYNOPSIS
*    int success = BreakSerial( int timeout, int duration );
*
* DESCRIPTION
*    Issue a SDCMD_BREAK to the Serial device with the break
*    duration given (success < 0 means the timer timed out). 
*******************************************************************
*
*/

VISIBLE int BreakSerial( int timeout, int duration )
{
   ULONG temp = 0L;
   
   KillTimer();   

   ReadRequest->IOSer.io_Command = SDCMD_BREAK;
   ReadRequest->io_BrkTime       = duration;
   TimeValue                     = timeout;

   StartTimer( timeout );

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;

         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;

         WaitIO( (struct IORequest *) ReadRequest );

         ErrorNumber = ReadRequest->IOSer.io_Error;

         return( (int) ReadRequest->IOSer.io_Actual );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;

         return( -1 );
         } 
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO( (struct IORequest *) ReadRequest );

   ErrorNumber = ReadRequest->IOSer.io_Error;

   return( (int) ReadRequest->IOSer.io_Actual );
}

/****h* QuerySerial() *********************************************
*
* NAME
*    QuerySerial()
*
* SYNOPSIS
*    int success = QuerySerial( int timeout );
*
* DESCRIPTION
*    Issue a SDCMD_QUERY to the Serial device (success < 0 means
*    the timer timed out). 
*******************************************************************
*
*/

VISIBLE int QuerySerial( int timeout )
{
   ULONG temp = 0L;
   
   KillTimer();   

   ReadRequest->IOSer.io_Command = SDCMD_QUERY;

   TimeValue = timeout;

   StartTimer( timeout );

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;

         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;

         WaitIO( (struct IORequest *) ReadRequest );

         SerialStatus = ReadRequest->io_Status;

         ErrorNumber = ReadRequest->IOSer.io_Error;

         return( (int) ReadRequest->IOSer.io_Actual );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;

         return( -1 );
         } 
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO(  (struct IORequest *) ReadRequest );

   SerialStatus = ReadRequest->io_Status;
   ErrorNumber  = ReadRequest->IOSer.io_Error;

   return( (int) ReadRequest->IOSer.io_Actual );
}

/****h* GetSerialStatus() *****************************************
*
* NAME
*    GetSerialStatus()
*
* SYNOPSIS
*    int success = GetSerialStatus( void );
*
* DESCRIPTION
*    Return the internal SerialStatus variable setting.
*******************************************************************
*
*/

VISIBLE int GetSerialStatus( void )
{
   return( SerialStatus );
}

/****h* SetSerialParams() *****************************************
*
* NAME
*    SetSerialParams()
*
* SYNOPSIS
*    int success = SetSerialParams( int timeout,
*                                   int whichparm,
*                                   int param
*                                 );
*
* DESCRIPTION
*    Issue a SDCMD_SETPARAMS to the Serial device for the given
*    parameter type & value (success < 0 means the timer timed 
*    out or an unknown value for whichparm).
*******************************************************************
*
*/

VISIBLE int SetSerialParams( int timeout, int which, int params )
{
   ULONG temp = 0L;

   switch (which)
      {
      case SETBAUD:
         ReadRequest->io_Baud = params;
         break;
      case SETSTOP:
         ReadRequest->io_StopBits = params;
         break;
      case SETFLAGS:
         ReadRequest->io_SerFlags = params;
         break;
      case SETEXTFLAGS:
         ReadRequest->io_ExtFlags = params;
         break;
      case SETREADLEN:
         ReadRequest->io_ReadLen = params;
         break;
      case SETWRITELEN:
         ReadRequest->io_WriteLen = params;
         break;
      case SETBREAKTIME:
         ReadRequest->io_BrkTime = params;
         break;
      case SETCTLCHAR:
         ReadRequest->io_CtlChar = params;
         break;
      case SETRBUFLEN:
         ReadRequest->io_RBufLen = params;
         break;
      default:
         return( -1 );
      }
         
   KillTimer();   

   ReadRequest->IOSer.io_Command = SDCMD_SETPARAMS;

   TimeValue = timeout;

   StartTimer( timeout );

   SendIO( (struct IORequest *) ReadRequest );

   while (1)
      {
      temp = Wait( WaitSerMask );

      if ((SIGBREAKF_CTRL_C & temp) == SIGBREAKF_CTRL_C)
         {
         TimedOut = FALSE;

         break;
         }

      if (CheckIO( (struct IORequest *) ReadRequest ))
         {
         TimedOut = FALSE;

         WaitIO( (struct IORequest *) ReadRequest );

         ErrorNumber = ReadRequest->IOSer.io_Error;

         return( (int) ReadRequest->IOSer.io_Actual );
         }
      else if (CheckIO( (struct IORequest *) SerTimer ) 
               && ( !SerTimer->tr_node.io_Error))
         {
         TimedOut = TRUE;

         return( -1 );
         } 
      }

   AbortIO( (struct IORequest *) ReadRequest );
   WaitIO(  (struct IORequest *) ReadRequest );

   ErrorNumber = ReadRequest->IOSer.io_Error;

   return( (int) ReadRequest->IOSer.io_Actual );
}

/* ----------------- End of TimedSerial.c file! ------------------ */
