[Back to COMM SWAG index]  [Back to Main SWAG index]  [Original]

{ ---------------------------------------------------------------------------
  unit COM.PAS

  Turbo Pascal (version 4.0 or higher) unit for serial communication which
  is based on interrupt routines and includes buffering of incoming data.

  Features:

  - supports COM1 and COM2 in parallel
  - baudrates up to 115200 baud
  - RTS/CTS and XON/XOFF flow control

  Version 3.0 - May 1994

  Copyright 1994, Willem van Schaik - Oirschot - Netherlands

  ---------------------------------------------------------------------------
}

  unit Com;

  interface

  uses Crt, Dos;

  type
    PortType = (COM1, COM2);
    BaudType = (B110, B150, B300, B600, B1200, B2400, B4800,
       B9600, B19200, B38400, B57600, B115200);
    ParityType = (None, Odd, Even, Mark, Space);
    LengthType = (D5, D6, D7, D8);
    StopType = (S1, S2);
    FlowType = (No, RtsCts, XonXoff);

  procedure InitCom (PortNumber : PortType;
         BaudRate : BaudType;
                     ParityBit : ParityType;
         DataLength : LengthType;
         StopBits : StopType;
         FlowControl : FlowType);
  procedure ExitCom (PortNumber : PortType);
  function  ComReceived (PortNumber : PortType) : boolean;
  function  ReadCom (PortNumber : PortType) : char;
  function  ComAllowed (PortNumber : PortType) : boolean;
  procedure WriteCom (PortNumber : PortType; OutByte : char);
  procedure BreakCom (PortNumber : PortType);

  implementation

  type
    IntBlock = record
      IntOldIP : integer;
      IntOldCS : integer;
      IntNumber : byte;
    end;

    INS8250 = record
      DLL : integer;  { divisor latch low register (if LCR bit7 = 1) }
      DLH : integer;  { divisor latch high register (if LCR bit7 = 1) }
      THR : integer;  { transmit holding register }
      RBR : integer;  { receive holding register }
      IER : integer;  { interrupt enable register }
      LCR : integer;  { line control register }
      MCR : integer;  { modem control register }
      LSR : integer;  { line status register }
      MSR : integer;  { modem status register }
    end;

  const
    IntDS : integer = 0;
    ComPort : array [COM1..COM2] of INS8250 =
      ((DLL : $3F8 ; DLH : $3F9 ; THR : $3F8 ; RBR : $3F8 ;
        IER : $3F9 ; LCR : $3FB ; MCR : $3FC ; LSR : $3FD ; MSR : $3FE),
       (DLL : $2F8 ; DLH : $2F9 ; THR : $2F8 ; RBR : $2F8 ;
        IER : $2F9 ; LCR : $2FB ; MCR : $2FC ; LSR : $2FD ; MSR : $2FE));
    { size of the input buffer and the amount of free space to disable flow
      from the other side and to enable it again }
    ComBufferSize = 4096;
    ComFlowLower = 256;
    ComFlowUpper = 1024;

  var
    ComBuffer : array [COM1 .. COM2, 0..(ComBufferSize-1)] of byte;
    ComBufferHead, ComBufferTail : array [COM1 .. COM2] of integer;
    ComFlowControl : array [COM1 .. COM2] of FlowType;
    ComFlowHalted : array [COM1 .. COM2] of boolean;
    ComXoffReceived : array [COM1 .. COM2] of boolean;
    ComBlock : array [COM1 .. COM2] of IntBlock;

{ ---------------------------------------------------------------------------
  InstallComInt

  To install an interrupt routine, first the old routine vector is read and
  stored using function 35 hex. Next the new routine is installed using
  function 25 hex.
  ---------------------------------------------------------------------------
}

  procedure InstallComInt (IntNumber : byte; IntHandler : integer;
                           var Block : IntBlock);
  var
    Regs : Registers;

  begin
    IntDS := DSeg;
    Block.IntNumber := IntNumber;
    Regs.AH := $35;
    Regs.AL := IntNumber;
    MSDos (Dos.Registers(Regs));
    Block.IntOldCS := Regs.ES;
    Block.IntOldIP := Regs.BX;
    Regs.AH := $25;
    Regs.AL := IntNumber;
    Regs.DS := CSeg;
    Regs.DX := IntHandler;
    MSDos (Dos.Registers(Regs));
  end;

{ ---------------------------------------------------------------------------
  UnInstallComInt

  Uninstalling the interrupt routine is done by resetting the old interrupt
  vector using function 25.
  ---------------------------------------------------------------------------
}

  procedure UnInstallComInt (var Block : IntBlock);

  var
    Regs : Registers;

  begin
    Regs.AH := $25;
    Regs.AL := Block.IntNumber;
    Regs.DS := Block.IntOldCS;
    Regs.DX := Block.IntOldIP;
    MSDos (Dos.Registers(Regs));
  end;

{ ---------------------------------------------------------------------------
  Com1IntHandler

  This routine is installed as the interrupt routine by InstallComInt, which
  in its turn is called by InitCom at initialisation of the unit.

  When a byte arrives at the COM-port, first action is to get the byte from
  the UART register and store it the buffer. Next the buffer pointer is
  increased. Depending on flow control being enabled or not, it is checked if
  the free space has become less then ComFlowLower and if that is the case the
  other party (the DCE) is signalled to stop transmitting data.

  When the type of flow control specified at calling InitCom is RtsCts (this
  is hardware flow control), the RTS bit of the MCR register is lowered. If
  flow control is XonXoff (software flow control), an XOFF character (13 hex)
  is send to the other party by calling WriteCom.

  Finally the routine must be ended with a CLI instruction and the interrupt
  flags must be cleared.
  ---------------------------------------------------------------------------
}

  procedure Com1IntHandler (Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP
: word);
  interrupt;

  begin
    ComBuffer[COM1, ComBufferHead[COM1]] := Port[ComPort[COM1].RBR];
    if ComFlowControl[COM1] = No then
    begin
      ComBufferHead[COM1] := (ComBufferHead[COM1] + 1) mod ComBufferSize;
    end
    else { when flow control increase buffer pointer later }
    begin
      { check for incoming XON/XOFF }
      if ComFlowControl[COM1] = XonXoff then
      begin
        if ComBuffer[COM1, ComBufferHead[COM1]] = $11 then { XON }
          ComXoffReceived[COM1] := false
        else if ComBuffer[COM1, ComBufferHead[COM1]] = $13 then { XOFF }
          ComXoffReceived[COM1] := true;
      end;
      ComBufferHead[COM1] := (ComBufferHead[COM1] + 1) mod ComBufferSize;
      { check if outgoing must be temporized }
      if not ComFlowHalted[COM1] then
        if (ComBufferHead[COM1] >= ComBufferTail[COM1]) and
   (ComBufferTail[COM1] - ComBufferHead[COM1] + ComBufferSize < ComFlowLower)
   or
   (ComBufferHead[COM1] < ComBufferTail[COM1]) and
   (ComBufferTail[COM1] - ComBufferHead[COM1] < ComFlowLower) then
        begin { buffer gets too full }
   if ComFlowControl[COM1] = RtsCts then
     Port[ComPort[COM1].MCR] := Port[ComPort[COM1].MCR] and $FD { lower RTS }
   else if ComFlowControl[COM1] = XonXoff then
     WriteCom (COM1, #$13); { send XOFF }
   ComFlowHalted[COM1] := true;
        end;
    end;
    inline ($FA);                         { CLI }
    Port[$20] := $20;                     { clear interrupt flag }
  end;

{ ---------------------------------------------------------------------------
  Com2IntHandler

  This routine is identical to Com1IntHandler, only for COM2.
  ---------------------------------------------------------------------------
}

  procedure Com2IntHandler (Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP : word);
  interrupt;

  begin
    ComBuffer[COM2, ComBufferHead[COM2]] := Port[ComPort[COM2].RBR];
    if ComFlowControl[COM2] = No then
    begin
      ComBufferHead[COM2] := (ComBufferHead[COM2] + 1) mod ComBufferSize;
    end
    else { when flow control increase buffer pointer later }
    begin
      { check for incoming XON/XOFF }
      if ComFlowControl[COM2] = XonXoff then
      begin
        if ComBuffer[COM2, ComBufferHead[COM2]] = $11 then { XON }
          ComXoffReceived[COM2] := false
        else if ComBuffer[COM2, ComBufferHead[COM2]] = $13 then { XOFF }
          ComXoffReceived[COM2] := true;
      end;
      ComBufferHead[COM2] := (ComBufferHead[COM2] + 1) mod ComBufferSize;
      { check if outgoing must be temporized }
      if not ComFlowHalted[COM2] then
        if (ComBufferHead[COM2] >= ComBufferTail[COM2]) and
   (ComBufferTail[COM2] - ComBufferHead[COM2] + ComBufferSize < ComFlowLower)
   or
   (ComBufferHead[COM2] < ComBufferTail[COM2]) and
   (ComBufferTail[COM2] - ComBufferHead[COM2] < ComFlowLower) then
        begin { buffer gets too full }
   if ComFlowControl[COM2] = RtsCts then
     Port[ComPort[COM2].MCR] := Port[ComPort[COM2].MCR] and $FD { lower RTS }
   else if ComFlowControl[COM2] = XonXoff then
     WriteCom (COM2, #$13); { send XOFF }
   ComFlowHalted[COM2] := true;
        end;
    end;
    inline ($FA);                         { CLI }
    Port[$20] := $20;                     { clear interrupt flag }
  end;

{ ---------------------------------------------------------------------------
  InitCom;

  For each of the COM ports that will be used, this routine must be called
  to initialize the UART and to install the interrrupt routine. The first
  five parameters define the serial protocol (baudrate B150..B11500, parity
  None..Space, length D5..D8 and number of stop bits S1 or S2). The last
  parameter specifies the type of flow control, with allowed values No,
  RtsCts and XonXoff.

  The control signals DTR and RTS of the COM port (plus the OUT2 signal, which
  is used by some internal modems) are raised to signal the other end of the
  line that the port is ready to receive data.
  ---------------------------------------------------------------------------
}

  procedure InitCom; { (PortNumber : PortType;
            BaudRate : BaudType;
                        ParityBit : ParityType;
            DataLength : LengthType;
            StopBits : StopType;
            FlowControl : FlowType); }
  const
    BaudReg : array [B110 .. B115200] of word =
      ($0417, $0300, $0180, $00C0, $0060, $0030,
       $0018, $000C, $0006, $0003, $0002, $0001);
    ParityReg : array [None..Space] of byte =
      ($00, $08, $18, $28, $38);
    LengthReg : array [D5 .. D8] of byte =
      ($00, $01, $02, $03);
    StopReg : array [S1 .. S2] of byte =
      ($00, $04);

  var
    Regs : Registers;

  begin
    { enable the interrupt (IRQ4 resp. IRQ3) for the specified COM port, by
      resetting the bits in the Interrupt Mask Register of the 8259 interrupt
      controller }
    if PortNumber = COM1 then
    begin
      InstallComInt($0C, Ofs(Com1IntHandler), ComBlock[COM1]);
      Port[$21] := Port[$21] and $EF
    end
    else if PortNumber = COM2 then
    begin
      InstallComInt($0B, Ofs(Com2IntHandler), ComBlock[COM2]);
      Port[$21] := Port[$21] and $F7
    end;

    Port[ComPort[PortNumber].LCR] := $80; { switch to write latch reg }
    Port[ComPort[PortNumber].DLH] := Hi (BaudReg [BaudRate]);
    Port[ComPort[PortNumber].DLL] := Lo (BaudReg [BaudRate]);
    Port[ComPort[PortNumber].LCR] := $00 or
         ParityReg [ParityBit] or
         LengthReg [DataLength] or
         StopReg [StopBits];
    Port[ComPort[PortNumber].IER] := $01; { enable interrupts }
    Port[ComPort[PortNumber].MCR] := $01 or { raise DTR }
                $02 or { raise RTS }
         $08;   { raise OUT2 }
    ComBufferHead[PortNumber] := 0;
    ComBufferTail[PortNumber] := 0;
    ComFlowControl[PortNumber] := FlowControl;
    ComFlowHalted[PortNumber] := false;
    ComXoffReceived[PortNumber] := false;
  end;

{ ---------------------------------------------------------------------------
  ExitCom;

  This routine must be called for each COM port in use, to remove the
  interrupt routine and to reset the control lines.
  ---------------------------------------------------------------------------
}

  procedure ExitCom; { (PortNumber : PortType) }

  var
    Regs : Registers;

  begin
    { disable the interrupt (IRQ4 resp. IRQ3) for the specified COM port, by
      setting the bits in the Interrupt Mask Register of the 8259 interrupt
      controller }
    if PortNumber = COM1 then
      Port[$21] := Port[$21] or $10
    else if PortNumber = COM2 then
      Port[$21] := Port[$21] or $08;

    Port[ComPort[PortNumber].LCR] := Port[ComPort[PortNumber].LCR] and $7F;
    Port[ComPort[PortNumber].IER] := 0; { disable interrupts }
    Port[ComPort[PortNumber].MCR] := 0; { lower DTR, RTS and OUT2 }
    UnInstallComInt(ComBlock[PortNumber]);
  end;

{ ---------------------------------------------------------------------------
  ComReceived;

  When the head and tail pointer (for writing resp. reading bytes) are not
  pointing to the same byte in the buffer, a byte has arrived from the UART
  and was stored in the buffer by the interrupt routine.
  ---------------------------------------------------------------------------
}

  function ComReceived; { (PortNumber : PortType) : boolean; }

  begin
    ComReceived := ComBufferHead[PortNumber] <> ComBufferTail[PortNumber];
  end;

{ ---------------------------------------------------------------------------
  ReadCom;

  Calling this function will wait for a byte in the buffer (if there is not
  yet one present) and then return it. The tail buffer pointer is increased
  and if flow from the other side was stopped, a check is made if the free
  space has again become more then ComFlowUpper. In that situation, depending
  on the type of flow control, either the RTS line is raised or and XON byte
  (11 hex) is send to the other party.
  ---------------------------------------------------------------------------
}

  function ReadCom; { (PortNumber : PortType) : char; }

  begin
    while ComBufferHead[PortNumber] = ComBufferTail[PortNumber] do Delay(10);
    ReadCom := char(ComBuffer[PortNumber, ComBufferTail[PortNumber]]);
    ComBufferTail[PortNumber] := (ComBufferTail[PortNumber] + 1) mod ComBufferSize;
    if (ComFlowControl[PortNumber] <> No) and ComFlowHalted[PortNumber] then
      if (ComBufferHead[PortNumber] >= ComBufferTail[PortNumber]) and
        (ComBufferTail[PortNumber] - ComBufferHead[PortNumber] + ComBufferSize > ComFlowUpper) or
        (ComBufferHead[PortNumber] < ComBufferTail[PortNumber]) and
        (ComBufferTail[PortNumber] - ComBufferHead[PortNumber] > ComFlowUpper)
then
      begin { buffer has emptied enough }
        if ComFlowControl[PortNumber] = RtsCts then
   Port[ComPort[PortNumber].MCR] := Port[ComPort[PortNumber].MCR] or $02 {
raise RTS }
        else if ComFlowControl[PortNumber] = XonXoff then
   WriteCom (PortNumber, #$11); { send XON }
        ComFlowHalted[PortNumber] := false;
      end;
  end;

{ ---------------------------------------------------------------------------
  ComAllowed;

  With this function it is possible to check if writing data to the COM port
  is allowed. When there is no flow control no check is made on any control
  line and the result will always be true. When hardware type flow control is
  enabled, DSR (and CD) and CTS must be high. In case of software flow
  control DSR must be high and a check is made if an XOFF byte was received.
  ---------------------------------------------------------------------------
}

  function  ComAllowed; { (PortNumber : PortType) : boolean; }

  begin
    ComAllowed := true;
    if (ComFlowControl[PortNumber] = RtsCts) then
    begin
      { replace in next line both $30 with $B0 for checking on CD, DSR and CTS}
      if ((Port[ComPort[PortNumber].MSR] and $30) <> $30) then { no DSR or CTS}
        ComAllowed := false;
    end
    else if (ComFlowControl[PortNumber] = XonXoff) then
    begin
      { replace in next line both $20 with $A0 for checking on CD and DSR }
      if ((Port[ComPort[PortNumber].MSR] and $20) <> $20) or { no DSR }
         (ComXoffReceived[PortNumber]) then { XOFF received }
        ComAllowed := false;
    end
  end;

{ ---------------------------------------------------------------------------
  WriteCom;

  This routine is to write a byte to the COM port. However, when necessary
  this will be delayed until the previous output byte is out the the UART.
  ---------------------------------------------------------------------------
}

  procedure WriteCom; { (PortNumber : PortType; OutByte : char); }

  begin
    while ((Port[ComPort[PortNumber].LSR] and $20) <> $20) do  { TD empty }
      Delay(1);
    Port[ComPort[PortNumber].THR] := byte(OutByte);
  end;

{ ---------------------------------------------------------------------------
  BreakCom;

  With this routine the TD line can be lowered for 200 msec, which is a so-
  called break signal.
  ---------------------------------------------------------------------------
}

  procedure BreakCom; { (PortNumber : PortType); }

  begin
    Port[ComPort[PortNumber].LCR] := Port[ComPort[PortNumber].LCR] or $40;
    Delay (200);  { 0.2 seconds }
    Port[ComPort[PortNumber].LCR] := Port[ComPort[PortNumber].LCR] and $BF;
  end;

  end.

{ ---------------------------------------------------------------------------
  end of COM.PAS
  ---------------------------------------------------------------------------
}

{ ---------------------------------------------------------------------------
  program TTY.PAS

  Sample terminal emulation using simple teletype protocol to be used with
  the unit COM.PAS for serial communnication.

  Features:

  - switching between COM1 and COM2
  - baudrates up to 115200 baud
  - RTS/CTS and XON/XOFF flow control
  - debug mode to display control characters

  Version 3.0 - May 1994

  Copyright 1994, Willem van Schaik - Oirschot - Netherlands

  ---------------------------------------------------------------------------
}

  program Tty;

  uses Crt, Com;

  const
    Ascii : array [0..255] of string [5] =
      ('<NUL>','<SOH>','<STX>','<ETX>','<EOT>','<ENQ>','<ACK>','<BEL>',
       '<BS>','<HT>','<LF>','<VT>','<FF>','<CR>','<SO>','<SI>',
       '<DLE>','<DC1>','<DC2>','<DC3>','<DC4>','<NAK>','<SYN>','<ETB>',
       '<CAN>','<EM>','<SUB>','<ESC>','<FS>','<GS>','<RS>','<US>',
       ' ','!','"','#','$','%','&','''','(',')','*','+',',','-','.','/',
       '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
       '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
       'P','Q','R','S','T','U','V','W','X','Y','Z','[','\',']','^','_',
       '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
       'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~','<DEL>',
       '<128>','<129>','<130>','<131>','<132>','<133>','<134>','<135>',
       '<136>','<137>','<138>','<139>','<140>','<141>','<142>','<143>',
       '<144>','<145>','<146>','<147>','<148>','<149>','<150>','<151>',
       '<152>','<153>','<154>','<155>','<156>','<157>','<158>','<159>',
       '<160>','<161>','<162>','<163>','<164>','<165>','<166>','<167>',
       '<168>','<169>','<170>','<171>','<172>','<173>','<174>','<175>',
       '<176>','<177>','<178>','<179>','<180>','<181>','<182>','<183>',
       '<184>','<185>','<186>','<187>','<188>','<189>','<190>','<191>',
       '<192>','<193>','<194>','<195>','<196>','<197>','<198>','<199>',
       '<200>','<201>','<202>','<203>','<204>','<205>','<206>','<207>',
       '<208>','<209>','<210>','<211>','<212>','<213>','<214>','<215>',
       '<216>','<217>','<218>','<219>','<220>','<221>','<222>','<223>',
       '<224>','<225>','<226>','<227>','<228>','<229>','<230>','<231>',
       '<232>','<233>','<234>','<235>','<236>','<237>','<238>','<239>',
       '<240>','<241>','<242>','<243>','<244>','<245>','<246>','<247>',
       '<248>','<249>','<250>','<251>','<252>','<253>','<254>','<255>');

  var
    TtyPort : PortType;
    TtyBaud : BaudType;
    TtyParity : ParityType;
    TtyLength : LengthType;
    TtyStop : StopType;
    TtyFlow : FlowType;

    ChCom, ChKey : char;
    DoDebug : boolean;
    GoExit : boolean;

{ ---------------------------------------------------------------------------
  TtyGetPars

  Procedure to handle alt-key combinations that are used to change the
  settings of the terminal emulation protocol.
  ---------------------------------------------------------------------------
}

  procedure TtyGetPars (AltKey : char);

  var
    ParsInput : string[16];

  begin
    case AltKey of

      #120:  { alt-1 }
      begin
        if WhereX > 1 then Writeln;
        Writeln ('TTY:  port = COM1:');
        if TtyPort <> COM1 then
        begin
          ExitCom (TtyPort);
          TtyPort := COM1;
          InitCom (TtyPort, TtyBaud, TtyParity, TtyLength, TtyStop, TtyFlow)
        end;
      end;

      #121:  { alt-2 }
      begin
        if WhereX > 1 then Writeln;
        Writeln ('TTY:  port = COM2:');
        if TtyPort <> COM2 then
        begin
          ExitCom (TtyPort);
          TtyPort := COM2;
          InitCom (TtyPort, TtyBaud, TtyParity, TtyLength, TtyStop, TtyFlow)
        end;
      end;

      #48:  { alt-B }
      begin
        if WhereX > 1 then Writeln;
        Write ('TTY:  baudrate = ');
        Readln (ParsInput);
        if (ParsInput = '3') or (ParsInput = '300') then TtyBaud := B300
        else if (ParsInput = '6') or (ParsInput = '600') then TtyBaud := B600
        else if (ParsInput = '12') or (ParsInput = '1200') then TtyBaud := B1200
        else if (ParsInput = '24') or (ParsInput = '2400') then TtyBaud := B2400
        else if (ParsInput = '48') or (ParsInput = '4800') then TtyBaud := B4800
        else if (ParsInput = '96') or (ParsInput = '9600') then TtyBaud := B9600
        else if (ParsInput = '192') or (ParsInput = '19200') then TtyBaud := B19200
        else if (ParsInput = '384') or (ParsInput = '38400') then TtyBaud := B38400
        else
          Writeln ('      baudrate = 300,600,1200,2400,4800,9600,19200,38400');
        ExitCom (TtyPort);
        InitCom (TtyPort, TtyBaud, TtyParity, TtyLength, TtyStop, TtyFlow);
      end;

      #38:  { alt-L }
      begin
        if WhereX > 1 then Writeln;
        Write ('TTY:  word length = ');
        Readln (ParsInput);
        case ParsInput[1] of
          '5': TtyLength := D5;
          '6': TtyLength := D6;
          '7': TtyLength := D7;
          '8': TtyLength := D8;
        else
          Writeln ('      word length = 5,6,7,8');
        end;
        ExitCom (TtyPort);
        InitCom (TtyPort, TtyBaud, TtyParity, TtyLength, TtyStop, TtyFlow);
      end;

      #25:  { alt-P }
      begin
        if WhereX > 1 then Writeln;
        Write ('TTY:  parity bit = ');
        Readln (ParsInput);
        case ParsInput[1] of
          'n', 'N': TtyParity := None;
          'o', 'O': TtyParity := Odd;
          'e', 'E': TtyParity := Even;
          'm', 'O': TtyParity := Mark;
          's', 'O': TtyParity := Space;
        else
          Writeln ('      parity bit = none,odd,even,mark,space');
        end;
        ExitCom (TtyPort);
        InitCom (TtyPort, TtyBaud, TtyParity, TtyLength, TtyStop, TtyFlow);
      end;

      #31:  { alt-S }
      begin
        if WhereX > 1 then Writeln;
        Write ('TTY:  stop bits = ');
        Readln (ParsInput);
        case ParsInput[1] of
          '1': TtyStop := S1;
          '2': TtyStop := S2;
        else
          Writeln ('      stop bits = 1,2');
        end;
        ExitCom (TtyPort);
        InitCom (TtyPort, TtyBaud, TtyParity, TtyLength, TtyStop, TtyFlow);
      end;

      #33:  { alt-F }
      begin
        if WhereX > 1 then Writeln;
        Write ('TTY:  flow control = ');
        Readln (ParsInput);
        case ParsInput[1] of
          'n', 'N': TtyFlow := No;
          'r', 'R': TtyFlow := RtsCts;
          'x', 'X': TtyFlow := XonXoff;
        else
          Writeln ('      flow control = no,rts/cts,xon/xoff');
        end;
        ExitCom (TtyPort);
        InitCom (TtyPort, TtyBaud, TtyParity, TtyLength, TtyStop, TtyFlow);
      end;

      #23:  { alt-I }
      begin
        if WhereX > 1 then Writeln;
        Write ('TTY:  port = COM', ord(TtyPort)+1, ':      ');
        case TtyBaud of
          B110: Write ('baudrate = 110          ');
          B150: Write ('baudrate = 150          ');
          B300: Write ('baudrate = 300          ');
          B600: Write ('baudrate = 600          ');
          B1200: Write ('baudrate = 1200         ');
          B2400: Write ('baudrate = 2400         ');
          B4800: Write ('baudrate = 4800         ');
          B9600: Write ('baudrate = 9600         ');
          B19200: Write ('baudrate = 19200        ');
          B38400: Write ('baudrate = 38400        ');
          B57600: Write ('baudrate = 57600        ');
          B115200: Write ('baudrate = 115200       ');
        end;
        case TtyParity of
          None: Writeln ('parity bit = none');
          Odd: Writeln ('parity bit = odd');
          Even: Writeln ('parity bit = even');
          Mark: Writeln ('parity bit = mark');
          Space: Writeln ('parity bit = space');
        end;
        case TtyFlow of
          No: Write ('      flow = no         ');
          RtsCts: Write ('      flow = rts/cts    ');
          XonXoff: Write ('      flow = xon/xoff   ');
        end;
        Write ('word length = ', ord(TtyLength)+5, '         ');
        Writeln ('stop bits = ', ord(TtyStop)+1);
      end;

      #35:  { alt-H }
      begin
        if WhereX > 1 then Writeln;
        Write ('TTY:  alt-1 - COM1      ');
        Write ('alt-B - baudrate        ');
        Write ('alt-I - info');
        Writeln;
        Write ('      alt-2 - COM2      ');
        Write ('alt-L - word length     ');
        Write ('alt-H - help');
        Writeln;
        Write ('      alt-F - flow      ');
        Write ('alt-P - parity bit');
        Writeln;
        Write ('      alt-D - debug     ');
        Write ('alt-S - stop bits       ');
        Write ('alt-X - exit');
        Writeln;
      end;

      #32:  { alt-D }
      begin
        DoDebug := not DoDebug;
        if WhereX > 1 then Writeln;
        if DoDebug then
          Writeln ('TTY:  debug = on')
        else
          Writeln ('TTY:  debug = off');
      end;

      #45:  { alt-X }
      begin
        if WhereX > 1 then Writeln;
        Writeln ('TTY:  exit');
        GoExit := true;
      end;

    end;  { case ChKey }
  end;  { procedure TtyGetPars }

{ ---------------------------------------------------------------------------

[Back to COMM SWAG index]  [Back to Main SWAG index]  [Original]