{ A set of routines to enable COM1 and COM2 to be accessed from Turbo Pascal.
  The following procedures are meant to be called by your programs:

  AssignAux(PortNumber in [1,2]) assigns AUX to COM1 or COM2
  AssignUsr(PortNumber in [1,2]) assigns USR to COM1 or COM2
  SetSerial(PortNumber in [1,2],
            BaudRate in [110,150,300,600,1200,2400,4800,9600],
            StopBits in [1,2],
            DataBits in [7,8],
            Parity in [None,Even,Odd]) sets the baud rate, stop bits, data
                               bits, and parity of one of the serial ports.

  The arrays InError and OutError may be examined to detect errors.  The bits
  are as follows:
     Bit 7 (128)        Time out (no device connected)
     Bit 3 (8)          Framing error
     Bit 2 (4)          Parity error
     Bit 1 (2)          Overrun error

  Function SerialStatus(PortNumber in [1,2]) returns a more complete status:
     Bit 15 (negative)  Time out (no device connected)
     Bit 14 (16384)     Transmission shift register empty
     Bit 13 (8192)      Transmission holding register empty
     Bit 12 (4096)      Break detect
     Bit 11 (2048)      Framing error
     Bit 10 (1024)      Parity error
     Bit 9  (512)       Overrun error
     Bit 8  (256)       Data ready
     Bit 7  (128)       Received line signal detect
     Bit 6  (64)        Ring indicator
     Bit 5  (32)        Data set ready
     Bit 4  (16)        Clear to send
     Bit 3  (8)         Delta receive line signal detect
     Bit 2  (4)         Trailing edge ring detector
     Bit 1  (2)         Delta data set ready
     Bit 0  (1)         Delta clear to send

  Identifiers starting with "__" are not meant to be used by the user program.
}

  Type
    __RegisterSet=Record Case Integer Of
                  1: (AX,BX,CX,DX,BP,DI,SE,DS,ES,Flags: Integer);
                  2: (AL,AH,BL,BH,CL,CH,DL,DH: Byte);
                End;
    __ParityType=(None,Even,Odd);

  Var
    __Regs: __RegisterSet;
    InError,OutError: Array [1..2] Of Byte;

  Procedure __Int14(PortNumber,Command,Parameter: Integer);
  { Do a BIOS COM driver interrupt }

    Begin
      With __Regs Do
       Begin
        DX:=PortNumber-1;
        AH:=Command;
        AL:=Parameter;
        Flags:=0;
        Intr($14,__Regs);
       End;
    End;


  Procedure SetSerial(PortNumber,BaudRate,StopBits,DataBits: Integer;
                      Parity: __ParityType);
  { Set serial parameters on a COM port }

    Var
      Parameter: Integer;

    Begin
      Case BaudRate Of
        110: BaudRate:=0;
        150: BaudRate:=1;
        300: BaudRate:=2;
        600: BaudRate:=3;
        1200: BaudRate:=4;
        2400: BaudRate:=5;
        4800: BaudRate:=6;
        Else BaudRate:=7; { Default to 9600 baud }
       End;
      If StopBits=2 Then StopBits:=1
      Else StopBits:=0; { Default to 1 stop bit }
      If DataBits=7 Then DataBits:=2
      Else DataBits:=3; { Default to 8 data bits }
      Parameter:=(BaudRate Shl 5)+(StopBits Shl 2)+DataBits;
      Case Parity Of
        Odd: Parameter:=Parameter+8;
        Even: Parameter:=Parameter+24;
        Else; { Default to no parity }
       End;
      __Int14(PortNumber,0,Parameter);
    End;


  Function SerialStatus(PortNumber: Integer): Integer;
  { Return the status of a COM port }

    Begin
      __Int14(PortNumber,3,0);
      SerialStatus:=__Regs.AX;
    End;


  Procedure __OutPort1(C: Byte);
  { Called by Write to AUX or USR when assigned to COM1 }

    Begin
      While (SerialStatus(1) And $30)=0 Do ;
      __Int14(1,1,C);
      OutError[1]:=OutError[1] Or (__Regs.AH And $8E);
    End;


  Procedure __OutPort2(C: Byte);
  { Called by Write to AUX or USR when assigned to COM2 }

    Begin
      While (SerialStatuS(2) And $30)=0 Do ;
      __Int14(2,1,C);
      OutError[2]:=OutError[2] Or (__Regs.AH And $8E);
    End;


  Function __InPort1: Char;
  { Called by Read from AUX or USR when assigned to COM1 }

    Begin
      __Int14(1,2,0);
      __InPort1:=Chr(__Regs.AL);
      InError[1]:=InError[1] Or (__Regs.AH And $8E);
    End;


  Function __InPort2: Char;
  { Called by Read from AUX or USR when assigned to COM2 }

    Begin
      __Int14(2,2,0);
      __InPort2:=Chr(__Regs.AL);
      InError[2]:=InError[2] Or (__Regs.AH And $8E);
    End;


  Procedure __AssignPort(PortNumber: Integer; Var InPtr,OutPtr: Integer);
  { Assign either AUX or USR to either COM1 or COM2 }

    Begin
      If PortNumber=2 Then
       Begin
        OutPtr:=Ofs(__OutPort2);
        InPtr:=Ofs(__InPort2);
       End
      Else { Default to port 1 }
       Begin
        OutPtr:=Ofs(__OutPort1);
        InPtr:=Ofs(__InPort1);
       End;
      InError[PortNumber]:=0;
      OutError[PortNumber]:=0;
    End;


  Procedure AssignAux(PortNumber: Integer);
  { Assign AUX to either COM1 or COM2 }

    Begin
      __AssignPort(PortNumber,AuxInPtr,AuxOutPtr);
    End;


  Procedure AssignUsr(PortNumber: Integer);
  { Assign USR to either COM1 or COM2 }

    Begin
      __AssignPort(PortNumber,UsrInPtr,UsrOutPtr);
    End;


{ See also SERTST.PAS in this XA for a little demo program using these
  procedures     }
