home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / PROG / PASCAL / MISCTI10.ZIP / TI226.ASC < prev    next >
Encoding:
Text File  |  1988-04-18  |  20.8 KB  |  628 lines

  1. PRODUCT : TURBO PASCAL     NUMBER : 226
  2. VERSION : 3.0xx
  3.      OS : PC-DOS
  4.    DATE : August 1, 1986
  5.  
  6.   TITLE : ASYNCHRONOUS COMMUNICATIONS
  7.  
  8. This  version  of Michael Quinlan's ASYNC.INC is compatible  with 
  9. IBM  PC  and  Compatibles.  It  gives  interrupt-driven  buffered 
  10. communication  capabilities to Turbo programs written for the IBM 
  11. PC.  It is heavily dependent on that hardware.
  12.  
  13. **NOTE:   Pages  12 through 15 contain an additional routine that 
  14. allows your program to change the communications parameters.
  15.  
  16. The  following example routines are public domain  programs  that 
  17. have  been uploaded to our Forum on CompuServe.  As a courtesy to 
  18. our  users  that  do not have  immediate  access  to  CompuServe, 
  19. Technical Support distributes these routines free of charge.
  20.  
  21. However,  because these routines are public domain programs,  not 
  22. developed by Borland International,  we are unable to provide any 
  23. technical support or assistance using these routines. If you need 
  24. assistance   using   these   routines,    or   are   experiencing 
  25. difficulties,  we  recommend  that you log  onto  CompuServe  and 
  26. request  assistance  from the Forum members that developed  these 
  27. routines.
  28.  
  29.  
  30. {--------------------------------------------------------------}
  31. {                        ASYNC.INC                             } 
  32. {                                                              } 
  33. {  Async Communication Routines                                } 
  34. {  by Michael Quinlan                                          } 
  35. {  with a bug fixed by Scott Herr                              }
  36. {  made PCjr-compatible by W. M. Miller                        }
  37. {  Highly dependent on the IBM PC and PC DOS 2.0               } 
  38. {                                                              }
  39. {  based on the DUMBTERM program by CJ Dunford                 }              
  40. {  in the January 1984                                         } 
  41. {  issue of PC Tech Journal.                                   } 
  42. {                                                              } 
  43. {  Entry points:                                               } 
  44. {    Async_Init                                                } 
  45. {      Performs initialization.                                }
  46. {                                                              } 
  47. {    Async_Open(Port, Baud : Integer;                          } 
  48. {               Parity : Char;                                 } 
  49. {               WordSize, StpBits : Integer) : Boolean         } 
  50. {   Sets up interrupt vector, initialize the COM port for      } 
  51. {   processing, sets pointers to the buffer.  Returns FALSE    }
  52.  
  53. {      port not installed.                                     }
  54. {                                                              }
  55. {    Async_Buffer_Check(var C : Char) : Boolean                }
  56. {      If a character is available, returns TRUE and moves the }
  57. {        character from the buffer to the parameter            }
  58. {      Otherwise, returns FALSE                                }
  59. {                                                              }
  60. {    Async_Send(C : Char)                                      }
  61. {      Transmits the character.                                }
  62.  
  63. {    Async_Send_String(S : LStr)                               }
  64. {      Calls Async_Send to send each character of S.           }
  65. {    Async_Close                                               }
  66. {    Turn off the COM port interrupts.                         }
  67. {    **MUST** BE CALLED BEFORE EXITING                         }
  68. {    YOUR PROGRAM; otherwise you                               }  
  69. {    will see some really strange errors and have to re-boot.  }
  70. {--------------------------------------------------------------}
  71.  
  72. { global declarations }
  73.  
  74. type
  75.   LStr = String[255];  { generic string type for parameters }
  76.  
  77. const
  78.   UART_THR = $00; 
  79.       { offset from base of UART Registers for IBM PC } 
  80.   UART_RBR = $00; 
  81.   UART_IER = $01; 
  82.   UART_IIR = $02; 
  83.   UART_LCR = $03; 
  84.   UART_MCR = $04; 
  85.   UART_LSR = $05; 
  86.   UART_MSR = $06; 
  87.  
  88.   I8088_IMR = $21;   
  89.        { port address of the Interrupt Mask Register } 
  90.  
  91. const 
  92.   Async_DSeg_Save : Integer = 0;  
  93.                      { Save DS reg in Code Segment 
  94.                      for interrupt routine } 
  95.  
  96. const
  97.   Async_Buffer_Max = 4095;
  98.  
  99. var 
  100.   Async_Buffer    : Array[0..Async_Buffer_Max] of char; 
  101.   Async_Open_Flag : Boolean;
  102.   Async_Port      : Integer; { current Open port number (1 or 2)
  103.   Async_Base      : Integer; { base for current open port } 
  104.   Async_Irq       : Integer; { irq for current open port } 
  105.  
  106.   Async_Buffer_Overflow : Boolean;  
  107.            { True if buffer overflow has happened } 
  108.   Async_Buffer_Used     : Integer; 
  109.   Async_MaxBufferUsed   : Integer; 
  110.  
  111.     { Async_Buffer is empty if Head = Tail } 
  112.   Async_Buffer_Head  : Integer;   
  113.            { Locn in Async_Buffer to put next char } 
  114.   Async_Buffer_Tail  : Integer;   
  115.            { Locn in Async_Buffer to get next char } 
  116.   Async_Buffer_NewTail : Integer;
  117.  
  118.   Async_BIOS_Port_Table : Array[1..2] of Integer absolute $40:0;
  119.     { This table is initialized by BIOS equipment determination
  120.     code at boot time to contain the base addresses for the
  121.     installed async adapters.  A value of 0 means "not in-
  122.     stalled." }
  123.  
  124. const 
  125.   Async_Num_Bauds = 8; 
  126.   Async_Baud_Table : array [1..Async_Num_Bauds] of record
  127.                                          Baud, Bits : integer
  128.                                       end
  129.                    = ((Baud:110;  Bits:$00), 
  130.                       (Baud:150;  Bits:$20), 
  131.                       (Baud:300;  Bits:$40), 
  132.                       (Baud:600;  Bits:$60), 
  133.                       (Baud:1200; Bits:$80), 
  134.                       (Baud:2400; Bits:$A0), 
  135.                       (Baud:4800; Bits:$C0), 
  136.                       (Baud:9600; Bits:$E0)); 
  137.  
  138.  
  139. procedure BIOS_RS232_Init(ComPort, ComParm : Integer); 
  140. { Issue Interrupt $14 to initialize the UART } 
  141. { See the IBM PC Technical Reference Manual 
  142.   for the format of ComParm } 
  143. var 
  144.   Regs : record 
  145.            ax, bx, cx, dx, bp, si, di, ds, es, flag : Integer 
  146.          end; 
  147. begin 
  148.   with Regs do 
  149.     begin 
  150.       ax := ComParm and $00FF;  { AH=0; AL=ComParm }
  151.       dx := ComPort;
  152.       Intr($14, Regs)
  153.     end 
  154. end; { BIOS_RS232_Init } 
  155.  
  156. procedure DOS_Set_Intrpt(v, s, o : integer); 
  157. { call DOS to set an interrupt vector } 
  158. var 
  159.   Regs : Record 
  160.            ax, bx, cx, dx, bp, si, di, ds, es, flag : integer 
  161.          end; 
  162. begin 
  163.   with Regs do 
  164.     begin 
  165.       ax := $2500 + (v and $00FF); 
  166.       ds := s; 
  167.       dx := o; 
  168.       MsDos(Regs) 
  169.     end 
  170. end; { DOS_Set_Intrpt } 
  171.  
  172. {----------------------------------------------------------} 
  173. {                                                          }
  174. {  ASYNCISR.INC - Interrupt Service Routine                }
  175. {                                                          }
  176. {----------------------------------------------------------} 
  177.  
  178. procedure Async_Isr; 
  179. { Interrupt Service Routine } 
  180. { Invoked when the UART has received a byte of data from the 
  181.   communication line } 
  182.  
  183. { re-written 9/14/84 to be entirely in machine language; 
  184.   original source left as comments } 
  185.  
  186. begin 
  187.  
  188.   {NOTE: on entry, Turbo Pascal has already PUSHed BP and SP } 
  189.   Inline( 
  190.       { save all registers used } 
  191.     $50/                           { PUSH AX } 
  192.     $53/                           { PUSH BX } 
  193.     $52/                           { PUSH DX } 
  194.     $1E/                           { PUSH DS } 
  195.     $FB/                           { STI } 
  196.    { set up the DS register to point to Turbo Pascal's data
  197. segment }
  198.     $2E/$FF/$36/Async_Dseg_Save/   { PUSH CS:Async_Dseg_Save }
  199.     $1F/                           { POP DS } 
  200.    { get the incoming character } 
  201.    { Async_Buffer[Async_Buffer_Head] 
  202.                   := Chr(Port[UART_RBR + Async_Base]); } 
  203.     $8B/$16/Async_Base/            { MOV DX,Async_Base } 
  204.     $EC/                           { IN AL,DX } 
  205.     $8B/$1E/Async_Buffer_Head/     { MOV BX,Async_Buffer_Head } 
  206.     $88/$87/Async_Buffer/          { MOV Async_Buffer[BX],AL } 
  207.       { Async_Buffer_NewHead := Async_Buffer_Head + 1; } 
  208.     $43/                           { INC BX } 
  209.       { if Async_Buffer_NewHead > Async_Buffer_Max then 
  210.           Async_Buffer_NewHead := 0; } 
  211.     $81/$FB/Async_Buffer_Max/      { CMP BX,Async_Buffer_Max } 
  212.     $7E/$02/                       { JLE L001 } 
  213.     $33/$DB/                       { XOR BX,BX } 
  214.       { if Async_Buffer_NewHead = Async_Buffer_Tail then 
  215.           Async_Buffer_Overflow := TRUE 
  216.         else } 
  217.  
  218. {L001:} 
  219.    $3B/$1E/Async_Buffer_Tail/     { CMP BX,Async_Buffer_Tail } 
  220.    $75/$08/                       { JNE L002 } 
  221.    $C6/$06/Async_Buffer_Overflow/$01/ { MOV
  222. Async_Buffer_Overflow,1 } 
  223.    $90/                           { NOP generated by assembler 
  224.                                     for some reason }
  225.    $EB/$16/                       { JMP SHORT L003 }
  226.      { begin 
  227.          Async_Buffer_Head := Async_Buffer_NewHead; 
  228.          Async_Buffer_Used := Async_Buffer_Used + 1; 
  229.          if Async_Buffer_Used > Async_MaxBufferUsed then 
  230.            Async_MaxBufferUsed := Async_Buffer_Used 
  231.        end; } 
  232. {L002:} 
  233.    $89/$1E/Async_Buffer_Head/     { MOV Async_Buffer_Head,BX } 
  234.    $FF/$06/Async_Buffer_Used/     { INC Async_Buffer_Used } 
  235.    $8B/$1E/Async_Buffer_Used/     { MOV BX,Async_Buffer_Used } 
  236.    $3B/$1E/Async_MaxBufferUsed/   { CMP BX,Async_MaxBufferUsed } 
  237.    $7E/$04/                       { JLE L003 } 
  238.    $89/$1E/Async_MaxBufferUsed/   { MOV Async_MaxBufferUsed,BX } 
  239. {L003:} 
  240.      { disable interrupts } 
  241.    $FA/                           { CLI } 
  242.      { Port[$20] := $20; }  { use non-specific EOI } 
  243.    $B0/$20/                       { MOV AL,20h } 
  244.    $E6/$20/                       { OUT 20h,AL } 
  245.      { restore the registers then use IRET to return } 
  246.      { the last two POPs are required because Turbo Pascal 
  247.        PUSHes these regs before we get control.  The manual 
  248.        doesn't so it, but that is what really happens }
  249.    $1F/                           { POP DS } 
  250.    $5A/                           { POP DX } 
  251.    $5B/                           { POP BX } 
  252.    $58/                           { POP AX } 
  253.    $5C/                           { POP SP } 
  254.    $5D/                           { POP BP } 
  255.    $CF)                           { IRET } 
  256. end; { Async_Isr } 
  257.  
  258. procedure Async_Init; 
  259. { initialize variables } 
  260. begin 
  261.   Async_DSeg_Save := DSeg; 
  262.   Async_Open_Flag := FALSE; 
  263.   Async_Buffer_Overflow := FALSE; 
  264.   Async_Buffer_Used := 0; 
  265.   Async_MaxBufferUsed := 0; 
  266. end; { Async_Init } 
  267.  
  268. procedure Async_Close; 
  269. { reset the interrupt system when UART interrupts 
  270.   no longer needed } 
  271. var
  272.   i, m : Integer;
  273. begin 
  274.   if Async_Open_Flag then 
  275.     begin 
  276.  
  277.       { disable the IRQ on the 8259 } 
  278.       Inline($FA);         { disable interrupts } 
  279.       i := Port[I8088_IMR];        
  280.                            { get the interrupt mask register } 
  281.       m := 1 shl Async_Irq;        
  282.                            { set mask to turn off interrupt } 
  283.       Port[I8088_IMR] := i or m; 
  284.  
  285.       { disable the 8250 data ready interrupt } 
  286.       Port[UART_IER + Async_Base] := 0; 
  287.  
  288.       { disable OUT2 on the 8250 } 
  289.       Port[UART_MCR + Async_Base] := 0; 
  290.       Inline($FB);          { enable interrupts }
  291.  
  292.       { re-initialize our data areas so 
  293.         we know the port is closed } 
  294.       Async_Open_Flag := FALSE 
  295.  
  296.     end 
  297. end; { Async_Close }
  298.  
  299. function Async_Open(ComPort       : Integer; 
  300.                     BaudRate      : Integer; 
  301.                     Parity        : Char; 
  302.                     WordSize      : Integer; 
  303.                     StopBits      : Integer) : Boolean; 
  304. { open a communications port } 
  305. var 
  306.   ComParm : Integer; 
  307.   i, m : Integer; 
  308. begin 
  309.   if Async_Open_Flag then Async_Close; 
  310.  
  311.   if (ComPort = 2) and (Async_BIOS_Port_Table[2] <> 0) then
  312.     Async_Port := 2
  313.   else
  314.     Async_Port := 1;  { default to COM1 }
  315.   Async_Base := Async_BIOS_Port_Table[Async_Port];
  316.   Async_Irq := Hi(Async_Base) + 1;
  317.  
  318.   if (Port[UART_IIR + Async_Base] and $00F8) <> 0 then 
  319.     Async_Open := FALSE 
  320.   else
  321.     begin 
  322.       Async_Buffer_Head := 0; 
  323.       Async_Buffer_Tail := 0; 
  324.       Async_Buffer_Overflow := FALSE; 
  325.  
  326.   { Build the ComParm for RS232_Init } 
  327.   { See Technical Reference Manual for description } 
  328.  
  329.       ComParm := $0000; 
  330.  
  331.   { Set up the bits for the baud rate } 
  332.       i := 0; 
  333.       repeat 
  334.         i := i + 1 
  335.       until (Async_Baud_Table[i].Baud = BaudRate) 
  336.               or (i = Async_Num_Bauds); 
  337.       ComParm := ComParm or Async_Baud_Table[i].Bits; 
  338.  
  339.       if Parity in ['E', 'e'] then ComParm := ComParm or $0018
  340.       else if Parity in ['O', 'o'] then 
  341.            ComParm := ComParm or $0008 
  342.       else ComParm := ComParm or $0000;  { default to No parity } 
  343.  
  344.       if WordSize = 7 then ComParm := ComParm or $0002 
  345.       else ComParm := ComParm or $0003;  { default to 8 data bits
  346. }
  347.  
  348.       if StopBits = 2 then ComParm := ComParm or $0004 
  349.       else ComParm := ComParm or $0000;  { default to 1 stop bit
  350.  
  351.       { use the BIOS COM port initialization routine 
  352.         to save typing the code } 
  353.  
  354.       BIOS_RS232_Init(Async_Port - 1, ComParm); 
  355.  
  356.       DOS_Set_Intrpt(Async_Irq + 8, CSeg, Ofs(Async_Isr)); 
  357.  
  358. { read the RBR and reset any possible pending error conditions  
  359.   first turn off the Divisor Access Latch Bit to allow 
  360.   access to RBR, etc. } 
  361.  
  362.       Inline($FA);  { disable interrupts } 
  363.  
  364.       Port[UART_LCR + Async_Base] := 
  365.               Port[UART_LCR + Async_Base] and $7F; 
  366.       { read the Line Status Register to reset any 
  367.         errors it indicates } 
  368.       i := Port[UART_LSR + Async_Base];
  369.       { read the Receiver Buffer Register in case 
  370.         it contains a character }
  371.       i := Port[UART_RBR + Async_Base]; 
  372.  
  373.       { enable the irq on the 8259 controller } 
  374.       i := Port[I8088_IMR];  { get the interrupt mask register } 
  375.       m := (1 shl Async_Irq) xor $00FF;
  376.       Port[I8088_IMR] := i and m; 
  377.  
  378.       { enable the data ready interrupt on the 8250 } 
  379.       Port[UART_IER + Async_Base] := $01; 
  380.       { enable data ready interrupt } 
  381.  
  382.       { enable OUT2 on 8250 } 
  383.       i := Port[UART_MCR + Async_Base]; 
  384.       Port[UART_MCR + Async_Base] := i or $08; 
  385.  
  386.       Inline($FB); { enable interrupts }
  387.       Async_Open_Flag := TRUE;  { bug fix by Scott Herr }
  388.       Async_Open := TRUE 
  389.     end 
  390. end; { Async_Open } 
  391.  
  392. function Async_Buffer_Check(var C : Char) : Boolean; 
  393. { see if a character has been received; return it if yes }
  394. begin
  395.   if Async_Buffer_Head = Async_Buffer_Tail then 
  396.     Async_Buffer_Check := FALSE 
  397.   else 
  398.     begin 
  399.       C := Async_Buffer[Async_Buffer_Tail];
  400.       Async_Buffer_Tail := Async_Buffer_Tail + 1; 
  401.       if Async_Buffer_Tail > Async_Buffer_Max then 
  402.         Async_Buffer_Tail := 0; 
  403.       Async_Buffer_Used := Async_Buffer_Used - 1; 
  404.       Async_Buffer_Check := TRUE 
  405.     end 
  406. end; { Async_Buffer_Check } 
  407.  
  408. procedure Async_Send(C : Char); 
  409. { transmit a character } 
  410. var 
  411.   i, m, counter : Integer; 
  412. begin 
  413.   Port[UART_MCR + Async_Base] := $0B; { turn on OUT2, DTR, and
  414. RTS } 
  415.  
  416.   { wait for CTS } 
  417.   counter := MaxInt;
  418.   while (counter <> 0) and 
  419.         ((Port[UART_MSR + Async_Base] and $10) = 0) do
  420.     counter := counter - 1; 
  421.  
  422.   { wait for Transmit Hold Register Empty (THRE) } 
  423.   if counter <> 0 then counter := MaxInt;
  424.   while (counter <> 0) and 
  425.         ((Port[UART_LSR + Async_Base] and $20) = 0) do
  426.     counter := counter - 1; 
  427.  
  428.   if counter <> 0 then 
  429.     begin 
  430.       { send the character } 
  431.       Inline($FA); { disable interrupts } 
  432.       Port[UART_THR + Async_Base] := Ord(C); 
  433.       Inline($FB) { enable interrupts } 
  434.     end 
  435.   else 
  436.     writeln('<<<TIMEOUT>>>'); 
  437. end; { Async_Send } 
  438.  
  439. procedure Async_Send_String(S : LStr); 
  440. { transmit a string } 
  441. var
  442.   i : Integer;
  443. begin 
  444.   for i := 1 to length(S) do
  445.     Async_Send(S[i])
  446. end; { Async_Send_String }
  447.  
  448. ________________________________________________________________
  449.  
  450.                         CHANGE PARAMETERS
  451. ________________________________________________________________
  452.  
  453. { ASYCHG.INC - procedure to change communication parameters }
  454. { "on the fly" must be Included following ASYNC.INC }
  455.  
  456. procedure Async_Change(BaudRate      : Integer;
  457.                        Parity        : Char;
  458.                        WordSize      : Integer;
  459.                        StopBits      : Integer);
  460. { change communication parameters "on the fly" }
  461. { you cannot use the BIOS routines because they drop DTR }
  462.  
  463. const num_bauds = 15;
  464.     divisor_table : array [1..num_bauds] of record
  465.                                             baud, divisor :
  466. integer
  467.                                           end
  468.        = ((baud:50;  divisor:2304),
  469.           (baud:75;  divisor:1536),
  470.           (baud:110; divisor:1047),
  471.           (baud:134; divisor:857),
  472.           (baud:150; divisor:768),
  473.           (baud:300; divisor:384),
  474.           (baud:600; divisor:192),
  475.           (baud:1200; divisor:96),
  476.           (baud:1800; divisor:64),
  477.           (baud:2000; divisor:58),
  478.           (baud:2400; divisor:48),
  479.           (baud:3600; divisor:32),
  480.           (baud:4800; divisor:24),
  481.           (baud:7200; divisor:16),
  482.           (baud:9600; divisor:12));
  483.  
  484. var i : integer;
  485.     dv  : integer;
  486.     lcr : integer;
  487.  
  488. begin
  489.  
  490.   { Build the Line Control Register and find 
  491.     the divisor (for the baud rate) }
  492.  
  493.   { Set up the divisor for the baud rate }
  494.   i := 0;
  495.   repeat
  496.     i := i + 1
  497.   until (Divisor_Table[i].Baud = BaudRate) or (i = Num_Bauds);
  498.   dv  := Divisor_Table[i].divisor;
  499.  
  500.   lcr := 0;
  501.   case Parity of
  502.     'E' : lcr := lcr or $18;  { even parity }
  503.     'O' : lcr := lcr or $08;  { odd parity }
  504.     'N' : lcr := lcr or $00;  { no parity }
  505.     'M' : lcr := lcr or $28;  { Mark parity }
  506.     'S' : lcr := lcr or $38;  { Space parity }
  507.   else
  508.     lcr := lcr or $00;  { default to no parity }
  509.   end;
  510.  
  511.   case WordSize of
  512.     5 : lcr := lcr or $00;
  513.     6 : lcr := lcr or $01;
  514.     7 : lcr := lcr or $02;
  515.     8 : lcr := lcr or $03;
  516.   else
  517.     lcr := lcr or $03;  { default to 8 data bits }
  518.   end;
  519.  
  520.   if StopBits = 2 then lcr := lcr or $04
  521.   else lcr := lcr or $00;  { default to 1 stop bit }
  522.  
  523.   lcr := lcr and $7F;   { make certain the DLAB is off }
  524.  
  525.   Inline($FA);  { disable interrupts }
  526.  
  527.   { turn on DLAB to access the divisor }
  528.   Port[UART_LCR + Async_Base] := Port[UART_LCR + Async_Base] or
  529. $80;
  530.  
  531.   { set the divisor }
  532.   Port[Async_Base] := Lo(dv);
  533.   Port[Async_Base + 1] := Hi(dv);
  534.  
  535.   { turn off the DLAB and set the new comm. parameters }
  536.   Port[UART_LCR + Async_Base] := lcr;
  537.  
  538.   Inline($FB);  { enable interrupts }
  539.  
  540. end; { Async_Change }
  541.  
  542. The following are two example programs which use ASYNC.INC.
  543.  
  544.   program DumbTerminal;
  545.   {$C-}
  546.   {$I ASYNC.INC}
  547.   var
  548.     ch: Char;
  549.     stop: Boolean;
  550.   begin
  551.     stop := false;
  552.     Async_Init;
  553.     if not Async_Open(1, 1200, 'E', 7, 1) then
  554.       begin
  555.         writeln('Invalid port');
  556.         Halt
  557.       end;
  558.     LowVideo;
  559.      writeln('COM1 now open at 1200 baud, 7 data bits, even
  560. parity, ',
  561.             '1 stop bit.');
  562.     write('All keyboard input will be sent out COM1');
  563.     writeln('all input from COM1');
  564.     writeln('will be displayed on the screen.  To quit, type
  565. ^Z.');
  566.     writeln;
  567.     repeat
  568.       if Async_Buffer_Check(ch) then write(ch);
  569.       if KeyPressed then
  570.         begin
  571.           read(Kbd, ch);
  572.           if ch = ^Z then stop := true else Async_Send(ch)
  573.         end
  574.     until stop;
  575.     Async_Close
  576.   end.
  577.  
  578.  
  579. program tty;
  580.  
  581. {$IASYNC.INC} 
  582.  
  583. var 
  584.   c : char; 
  585.  
  586. begin 
  587.   Async_Init;  { initialize variables } 
  588.   if not Async_Open(1, 1200, 'E', 7, 1) then  {open
  589. communications port} 
  590.     begin 
  591.       writeln('**ERROR: Async_Open failed'); 
  592.       halt 
  593.     end; 
  594.  
  595.   writeln('TTY Emulation begins now...'); 
  596.   writeln('Press any function key to terminate...'); 
  597.  
  598.   repeat 
  599.     if Async_Buffer_Check(c) then 
  600.       case c of 
  601.         #000 : ;  { strip incoming nulls } 
  602.         #010 : ;  { strip incoming line feeds } 
  603.         #012 : ClrScr;  { clear screen on a form feed } 
  604.         #013 : Writeln  { handle carriage return as CR/LF } 
  605.       else 
  606.         write(c)  { else write incoming char to the screen } 
  607.       end; { case } 
  608.     if KeyPressed then 
  609.       begin 
  610.         Read(Kbd, c); 
  611.         if c = #027 then  { handle IBM Extended Ascii codes } 
  612.           begin 
  613.             Read(Kbd, c);  { clear the rest of the extended code
  614.             Async_Close;   { reset the interrupt system, etc. } 
  615.             Writeln('End of TTY Emulation...'); 
  616.             Writeln('Max Buffer Used = ', Async_MaxBufferUsed); 
  617.             halt          { terminate the program } 
  618.           end 
  619.         else 
  620.           Async_Send(c)
  621.       end
  622.   until FALSE
  623.  
  624. end.
  625.