Uses Crt,Dos;

Const
  RxR=0;                        {Receive Data, bei Lesezugriffen}
  TxR=0;                        {Transmit Data, bei Schreibzugriffen}
  IER=1;                        {Interrupt Enable}
  IIR=2;                        {Interrupt Identification}
  LCR=3;                        {Line Control}
  MCR=4;                        {Modem Control}
  LSR=5;                        {Line Status}
  MSR=6;                        {Modem Status}
  DLL=0;                        {Divisor Latch High}
  DLH=1;                        {Divisor Latch Low}

  N=0;                          {keine Paritt}
  O=8;                          {ungerade Paritt}
  E=24;                         {gerade Paritt}

  IRQ_Tab:Array[1..4] of Word   {Interrupt-Nummern der Schnittsctellen}
    =(4,3,4,3);
  Base_Tab:Array[1..4] of Word  {Portadressen der Schnittstellen}
    =($3f8,$2f8,$3e8,$2e8);

Var OldInt:Pointer;             {originaler Interrupt-Vektor}
    Key:Char;                   {gedrckte Taste}
    IRQ,                        {IRQ-Nummer des aktuellen Ports}
    Base:Word;                  {Portadresse des aktuellen Ports}
    fertig:Boolean;             {Flag fr Programm-Ende}

Procedure Handler;interrupt;
{Interrupt-Handler, nimmt Zeichen von ser. Port entgegen}
Begin
  Write(Chr(Port[Base+RxR]));   {Zeichen vom Port holen und ausgeben}
  Port[$20]:=$20;               {EOI senden}
End;

Procedure Open_Port(Nr:Word);
{bereitet COM-Port auf Ein-/Ausgabe vor}
Begin
  IRQ:=IRQ_Tab[Nr];             {IRQ-Nummer holen}
  Base:=Base_Tab[Nr];           {Basis-Adress holen}
  GetIntVec(IRQ+8,OldInt);      {Zeiger verbiegen}
  SetIntVec(IRQ+8,@Handler);
  Port[$21]:=Port[$21] and      {IRQ zulassen}
    not (1 shl IRQ);
  Port[Base+MCR]:=11;           {Auxiliary Output, RTS und DTR setzen}
  Port[Base+IER]:=1;            {Interrupt Enable fr Receive}
End;

Procedure Close_Port;
{setzt COM-Interrupts zurck}
Begin
  SetIntVec(IRQ+8,OldInt);      {IRQ-Vektor wiederherstellen}
  Port[Base+MCR]:=0;            {Signale zurcksetzen}
  Port[Base+IER]:=0;            {Interrupts ausschalten}
  Port[$21]:=                   {Interrupt-Controller zurcksetzen}
    Port[$21] or (1 shl IRQ);
End;

Procedure Set_Speed(bps:LongInt);
{setzt Port-Geschwindigkeit}
Var Divisor:Word;
Begin
  Port[Base+LCR]:=Port[Base+LCR]{DLAB einschalten}
    or 128;
  Divisor:=115200 div bps;
  Port[Base+DLL]:=Lo(Divisor);  {Werte in Divsor Latch schreiben}
  Port[BAse+DLH]:=Hi(Divisor);
  Port[Base+LCR]:=Port[Base+LCR]{DLAB ausschalten}
    and not 128;
End;

Procedure Set_Param(Data,Par,Stop:Word);
{setzt die Parameter Datenbits, Paritt und Stopbits}
Begin
  Port[Base+LCR]:=
    (Data-5)                    {Bit 0-1 auf Datenbit setzen}
    + Par                       {Paritt dazu}
    + (Stop-1) shl 2;           {Stopbits in Bit 2 des LCR setzen}
End;

Procedure Error;
{wird bei Time-Out in der Sende-Prozedur aufgerufen}
Begin
  WriteLn;
  WriteLn('Sende-Timeout');     {Meldung}
  Close_Port;                   {Port schlieen}
  Halt(1);                      {und abbrechen}
End;

Procedure Transmit(c:Char);
{sendet Zeichen ber seriellen Port}
Var Time_Out:Integer;           {Zhler fr Time-Out}
Begin
  Time_Out:=-1;
  While Port[Base+MSR] and 16 = 0 Do Begin
    Dec(Time_Out);              {Warten auf CTS}
    If Time_Out=0 Then Error;
  End;
  Time_Out:=-1;
  While Port[Base+LSR] and 32 = 0 Do Begin
    Dec(Time_Out);              {Warten auf leeres Transmitter-Register}
    If Time_Out=0 Then Error;
  End;
  Port[Base+TxR]:=Ord(c);       {Zeichen senden}
End;

Begin
  Open_Port(2);                 {COM ffnen}
  Set_Speed(19200);             {Geschwindigkeit 19200 bps}
  Set_Param(8,N,1);             {Parameter setzen}
  WriteLn;
  WriteLn('Terminal in Funktion (Alt-X zum Beenden):');
  Repeat
    Key:=ReadKey;               {Taste lesen}
    If Key <> #0 Then           {normale Tasten an COM-Port senden}
      Transmit(Key)
    Else                        {bei Alt-X beenden}
      If ReadKey=#45 Then fertig:=true;
  Until fertig;
  Close_Port;                   {Interrupts ausschalten}
End.
