home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / mods / pk232src / sss_asyn.pas < prev    next >
Pascal/Delphi Source File  |  1986-09-09  |  36KB  |  791 lines

  1.     {----------------------------------------------------------------------}
  2.     {   Asynchronous I/O routines of the Split-Screen Server (SSS)         }
  3.     {----------------------------------------------------------------------}
  4.     {                                                                      }
  5.     {  Author:  Philip R. Burns ("PIBASYNC.PAS", from SIG disk)            }
  6.     {  Date:    January, 1985                                              }
  7.     {  Version: 1.0                                                        }
  8.     {  Systems: For MS-DOS on IBM PCs and close compatibles only.          }
  9.     {                                                                      }
  10.     {  Modified (adapted) by HB9CVV                                        }
  11.     {                                                                      }
  12.     {----------------------------------------------------------------------}
  13.     {                                                                      }
  14.     {  Routines:                                                           }
  15.     {                                                                      }
  16.     {     Async_Init             ---    Performs initialization.           }
  17.     {     Async_Open             ---    Sets up COM port                   }
  18.     {     Async_Close            ---    Closes down COM port               }
  19.     {     Async_Buffer_Check     ---    Checks if character in COM buffer  }
  20.     {     Async_Receive          ---    Reads character from COM buffer    }
  21.     {     Async_Send             ---    Transmits char over COM port       }
  22.     {----------------------------------------------------------------------}
  23.  
  24.  
  25.     {----------------------------------------------------------------------}
  26.     {                                                                      }
  27.     {                  COMMUNICATIONS HARDWARE ADDRESSES                   }
  28.     {                                                                      }
  29.     {        These are specific to IBM PCs and close compatibles.          }
  30.     {                                                                      }
  31.     {----------------------------------------------------------------------}
  32.  
  33.   TYPE RegPack =
  34.     RECORD AX, BX, CX, DX, BP, SI, DI, DS, ES, FLAGS : Integer
  35.     END;
  36.  
  37.   CONST
  38.  
  39.     UART_THR = $00;                     { offset from base of UART Registers for IBM PC }
  40.     UART_RBR = $00;
  41.     UART_IER = $01;
  42.     UART_IIR = $02;
  43.     UART_LCR = $03;
  44.     UART_MCR = $04;
  45.     UART_LSR = $05;
  46.     UART_MSR = $06;
  47.     UART_DLL = $00;
  48.     UART_DLM = $01;
  49.  
  50.     I8088_IMR = $21;                    { port address of the Interrupt Mask Register }
  51.  
  52.     COM_Base : ARRAY[1..6] OF Integer =
  53.  
  54.     ($03F8, { COM1 }                    { Address of the UART }
  55.     $02F8,                              { COM2 }
  56.     $03E8,                              { COM3 }
  57.     $03E0,                              { COM4 }
  58.     $02F0,                              { COM5 }
  59.     $02E8);                             { COM6 }
  60.  
  61.     COM_Irq : ARRAY[1..6] OF Integer =
  62.  
  63.     (4, { COM1 }                        { Interrupt Line for the UART }
  64.     3,                                  { COM2 }
  65.     4,                                  { COM3 }
  66.     3,                                  { COM4 }
  67.     4,                                  { COM5 }
  68.     3);                                 { COM6 }
  69.  
  70.   CONST
  71.  
  72.     Async_DSeg_Save : Integer = 0;      { Save DS reg in Code Segment for }
  73.     { interrupt routine               }
  74.  
  75.     {----------------------------------------------------------------------}
  76.     {                                                                      }
  77.     {                   COMMUNICATIONS BUFFER VARIABLES                    }
  78.     {                                                                      }
  79.     {     The Communications Buffer is implemented as a circular (ring)    }
  80.     {     buffer, or double-ended queue.  The asynchronous I/O routines    }
  81.     {     enter characters in the buffer as they are received.  Higher-    }
  82.     {     level routines may extract characters from the buffer.           }
  83.     {                                                                      }
  84.     {     Note that this buffer is used for input only;  output is done    }
  85.     {     on a character-by-character basis.                               }
  86.     {                                                                      }
  87.     {----------------------------------------------------------------------}
  88.  
  89.   CONST
  90.  
  91.     Async_Buffer_Max = 8191;            { Size of Communications Buffer   }
  92.     Async_Loops_Per_Sec = 6500;         { Loops per second -- 4.77 clock  }
  93.     TimeOut = 256;                      { TimeOut value                   }
  94.  
  95.   VAR
  96.     { Communications Buffer Itself }
  97.  
  98.     Async_Buffer : ARRAY[0..Async_Buffer_Max] OF Char;
  99.  
  100.     Async_Open_Flag : Boolean;          { true if Open but no Close         }
  101.     Async_Port : Integer;               { current Open port number (1 or 2) }
  102.     Async_Base : Integer;               { base for current open port        }
  103.     Async_Irq : Integer;                { irq for current open port         }
  104.  
  105.     Async_Buffer_Overflow : Boolean;    { True if buffer overflow has happened }
  106.     Async_Buffer_Used : Integer;
  107.     Async_MaxBufferUsed : Integer;
  108.  
  109.     { Async_Buffer empty if Head = Tail    }
  110.     Async_Buffer_Head : Integer;        { Loc in Async_Buffer to put next char }
  111.     Async_Buffer_Tail : Integer;        { Loc in Async_Buffer to get next char }
  112.     Async_Buffer_NewTail : Integer;
  113.  
  114.     Async_SaveVector_CS : Integer;      { Saved segment of Interrupt routine }
  115.     Async_SaveVector_IP : Integer;      { Saved offset of Interrupt routine }
  116.  
  117.     Async_Blocked : Boolean;            { TRUE if ^S received, reset by ^Q }
  118.  
  119.     {----------------------------------------------------------------------}
  120.     {             DOS_Set_Intrpt --- Call DOS to set interrupt vector      }
  121.     {----------------------------------------------------------------------}
  122.  
  123.   PROCEDURE DOS_Set_Intrpt(v, s, o : Integer);
  124.  
  125.       {                                                                      }
  126.       {     Procedure:  DOS_Set_Intrpt                                       }
  127.       {                                                                      }
  128.       {     Purpose:    Calls DOS to set interrupt vector                    }
  129.       {                                                                      }
  130.       {     Calling Sequence:                                                }
  131.       {                                                                      }
  132.       {        DOS_Set_Intrpt( v, s, o : Integer );                          }
  133.       {                                                                      }
  134.       {           v --- interrupt vector number to set                       }
  135.       {           s --- segment address of interrupt routine                 }
  136.       {           o --- offset address of interrupt routine                  }
  137.       {                                                                      }
  138.       {      Calls:   MSDOS   (to set interrupt)                             }
  139.       {                                                                      }
  140.  
  141.     VAR
  142.       Regs : Regpack;
  143.  
  144.     BEGIN                               { DOS_Set_Intrpt }
  145.  
  146.       INLINE($FA);                      {  cli        disable interrupts       }
  147.       WITH Regs DO
  148.         BEGIN
  149.           Ax := $3500+(v AND $00FF);
  150.           MsDos(Regs);                  {  DOS function 35 - get vector        }
  151.           Ds := s;
  152.           Dx := o;
  153.           Async_SaveVector_CS := Es;
  154.           Async_SaveVector_IP := Bx;
  155.           Ax := $2500+(v AND $00FF);
  156.           MsDos(Regs);
  157.         END;
  158.       INLINE($FB);                      {  sti        re-enable ints           }
  159.  
  160.     END { DOS_Set_Intrpt } ;
  161.  
  162.     {----------------------------------------------------------------------}
  163.     {               Async_Isr --- Interrupt Service Routine                }
  164.     {----------------------------------------------------------------------}
  165.  
  166.   PROCEDURE Async_Isr;
  167.  
  168.       {                                                                      }
  169.       {     Procedure:  Async_Isr                                            }
  170.       {                                                                      }
  171.       {     Purpose:    Invoked when UART has received character from        }
  172.       {                 communications line  (asynchronous)                  }
  173.       {                                                                      }
  174.       {     Calling Sequence:                                                }
  175.       {                                                                      }
  176.       {        Async_Isr;                                                    }
  177.       {                                                                      }
  178.       {           --- Called asyncronously only!!!!!!                        }
  179.       {                                                                      }
  180.       {     Remarks:                                                         }
  181.       {                                                                      }
  182.       {        This is Michael Quinlan's version of the interrupt handler.   }
  183.       {                                                                      }
  184.  
  185.     BEGIN                               { Async_Isr }
  186.  
  187.       {  NOTE: on entry, Turbo Pascal has already PUSHed BP and SP  }
  188.  
  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 segment }
  197.         $2E/$FF/$36/Async_Dseg_Save/    { PUSH CS:Async_Dseg_Save }
  198.         $1F/                            { POP DS }
  199.         { get the incomming character }
  200.         { Async_Buffer[Async_Buffer_Head] := Chr(Port[UART_RBR + Async_Base]); }
  201.         $8B/$16/Async_Base/             { MOV DX,Async_Base }
  202.         $EC/                            { IN AL,DX }
  203.         $8B/$1E/Async_Buffer_Head/      { MOV BX,Async_Buffer_Head }
  204.         $88/$87/Async_Buffer/           { MOV Async_Buffer[BX],AL }
  205.  
  206.         { if chr=^S THEN Async_Blocked := TRUE
  207.         if chr=^Q THEN Async_Blocked := FALSE }
  208.  
  209.         $3C/$13/                        { CMP AL,013H }
  210.         $75/$07/                        { JNE Z001 }
  211.         $C6/$06/Async_Blocked/$01/      { MOV Async_Blocked,1 }
  212.         $EB/$09/                        { JMP Z002 }
  213.         {Z001:}
  214.         $3C/$11/                        { CMP AL,011H }
  215.         $75/$05/                        { JNE Z002 }
  216.         $C6/$06/Async_Blocked/$00/      { MOV Async_Blocked,0 }
  217.         {Z002:}
  218.  
  219.         { Async_Buffer_NewHead := Async_Buffer_Head + 1; }
  220.         $43/                            { INC BX }
  221.         { if Async_Buffer_NewHead > Async_Buffer_Max then
  222.         Async_Buffer_NewHead := 0; }
  223.         $81/$FB/Async_Buffer_Max/       { CMP BX,Async_Buffer_Max }
  224.         $7E/$02/                        { JLE L001 }
  225.         $33/$DB/                        { XOR BX,BX }
  226.         { if Async_Buffer_NewHead = Async_Buffer_Tail then
  227.         Async_Buffer_Overflow := TRUE
  228.         else }
  229.         {L001:}
  230.         $3B/$1E/Async_Buffer_Tail/      { CMP BX,Async_Buffer_Tail }
  231.         $75/$08/                        { JNE L002 }
  232.         $C6/$06/Async_Buffer_Overflow/$01/ { MOV Async_Buffer_Overflow,1 }
  233.         $90/                            { NOP generated by assembler for some reason }
  234.         $EB/$16/                        { JMP SHORT L003 }
  235.         { begin
  236.         Async_Buffer_Head := Async_Buffer_NewHead;
  237.         Async_Buffer_Used := Async_Buffer_Used + 1;
  238.         if Async_Buffer_Used > Async_MaxBufferUsed then 
  239.         Async_MaxBufferUsed := Async_Buffer_Used
  240.         end; }
  241.         {L002:}
  242.         $89/$1E/Async_Buffer_Head/      { MOV Async_Buffer_Head,BX }
  243.         $FF/$06/Async_Buffer_Used/      { INC Async_Buffer_Used }
  244.         $8B/$1E/Async_Buffer_Used/      { MOV BX,Async_Buffer_Used }
  245.         $3B/$1E/Async_MaxBufferUsed/    { CMP BX,Async_MaxBufferUsed }
  246.         $7E/$04/                        { JLE L003 }
  247.         $89/$1E/Async_MaxBufferUsed/    { MOV Async_MaxBufferUsed,BX }
  248.         {L003:}
  249.         { disable interrupts }
  250.         $FA/                            { CLI }
  251.         { Port[$20] := $20; }           { use non-specific EOI }
  252.         $B0/$20/                        { MOV AL,20h }
  253.         $E6/$20/                        { OUT 20h,AL }
  254.         { restore the registers then use IRET to return }
  255.         { the last two POPs are required because Turbo Pascal PUSHes these regs
  256.         before we get control.  The manual doesn't say so, but that is what
  257.         really happens }
  258.         $1F/                            { POP DS }
  259.         $5A/                            { POP DX }
  260.         $5B/                            { POP BX }
  261.         $58/                            { POP AX }
  262.         $5C/                            { POP SP }
  263.         $5D/                            { POP BP }
  264.         $CF)                            { IRET }
  265.  
  266.     END { Async_Isr } ;
  267.  
  268.     {----------------------------------------------------------------------}
  269.     {               Async_Init --- Initialize Asynchronous Variables       }
  270.     {----------------------------------------------------------------------}
  271.  
  272.   PROCEDURE Async_Init;
  273.  
  274.       {                                                                      }
  275.       {     Procedure:  Async_Init                                           }
  276.       {                                                                      }
  277.       {     Purpose:    Initializes variables                                }
  278.       {                                                                      }
  279.       {     Calling Sequence:                                                }
  280.       {                                                                      }
  281.       {        Async_Init;                                                   }
  282.       {                                                                      }
  283.       {     Calls:  None                                                     }
  284.       {                                                                      }
  285.  
  286.     BEGIN                               { Async_Init }
  287.  
  288.       Async_DSeg_Save := DSeg;
  289.       Async_Open_Flag := False;
  290.       Async_Buffer_Overflow := False;
  291.       Async_Buffer_Used := 0;
  292.       Async_MaxBufferUsed := 0;
  293.       Async_Blocked := False;
  294.  
  295.     END { Async_Init } ;
  296.  
  297.     {----------------------------------------------------------------------}
  298.     {               Async_Close --- Close down communications interrupts   }
  299.     {----------------------------------------------------------------------}
  300.  
  301.   PROCEDURE Async_Close;
  302.  
  303.       {                                                                      }
  304.       {     Procedure:  Async_Close                                          }
  305.       {                                                                      }
  306.       {     Purpose:    Resets interrupt system when UART interrupts         }
  307.       {                 are no longer needed.                                }
  308.       {                                                                      }
  309.       {     Calling Sequence:                                                }
  310.       {                                                                      }
  311.       {        Async_Close;                                                  }
  312.       {                                                                      }
  313.       {     Calls:  None                                                     }
  314.       {                                                                      }
  315.  
  316.     VAR
  317.       i : Integer;
  318.       m : Integer;
  319.  
  320.     BEGIN                               { Async_Close }
  321.  
  322.       IF Async_Open_Flag THEN
  323.         BEGIN
  324.  
  325.           { disable the IRQ on the 8259 }
  326.  
  327.           INLINE($FA);                  { disable interrupts }
  328.  
  329.           i := Port[I8088_IMR];         { get the interrupt mask register }
  330.           m := 1 SHL Async_Irq;         { set mask to turn off interrupt  }
  331.           Port[I8088_IMR] := i OR m;
  332.  
  333.           { disable the 8250 data ready interrupt }
  334.  
  335.           Port[UART_IER+Async_Base] := 0;
  336.  
  337.           { disable OUT2 on the 8250 }
  338.  
  339.           Port[UART_MCR+Async_Base] := 0;
  340.  
  341.           DOS_Set_Intrpt(Async_Irq+8, Async_SaveVector_CS, Async_SaveVector_IP);
  342.  
  343.           INLINE($FB);                  { enable interrupts }
  344.  
  345.           { re-initialize our data areas so we know }
  346.           { the port is closed                      }
  347.  
  348.           Async_Open_Flag := False;
  349.  
  350.         END;
  351.  
  352.     END { Async_Close } ;
  353.  
  354.     {----------------------------------------------------------------------}
  355.     {               Async_Open --- Open communications port                }
  356.     {----------------------------------------------------------------------}
  357.  
  358.   FUNCTION Async_Open(ComPort : Integer;
  359.                       BaudRate : Integer;
  360.                       Parity : Char;
  361.                       WordSize : Integer;
  362.                       StopBits : Integer) : Boolean;
  363.  
  364.       {                                                                      }
  365.       {     Function:   Async_Open                                           }
  366.       {                                                                      }
  367.       {     Purpose:    Opens communications port                            }
  368.       {                                                                      }
  369.       {     Calling Sequence:                                                }
  370.       {                                                                      }
  371.       {        Flag := Async_Open( ComPort       : Integer;                  }
  372.       {                            BaudRate      : Integer;                  }
  373.       {                            Parity        : Char;                     }
  374.       {                            WordSize      : Integer;                  }
  375.       {                            StopBits      : Integer) : Boolean;       }
  376.       {                                                                      }
  377.       {           ComPort  --- which port (1 or 2)                           }
  378.       {           BaudRate --- Baud rate (110 to 9600)                       }
  379.       {           Parity   --- "E" for even, "O" for odd, "N" for none       }
  380.       {           WordSize --- Bits per character  (5 through 8)             }
  381.       {           StopBits --- How many stop bits  (1 or 2)                  }
  382.       {                                                                      }
  383.       {           Flag returned TRUE if port initialized successfully;       }
  384.       {           Flag returned FALSE if any errors.                         }
  385.       {                                                                      }
  386.       {     Calls:                                                           }
  387.       {                                                                      }
  388.       {        DOS_Set_Intrpt  --- set address of RS232 interrupt routine    }
  389.       {                                                                      }
  390.  
  391.     CONST                               { Baud Rate Constants }
  392.  
  393.       Async_Num_Bauds = 8;
  394.  
  395.       Async_Baud_Table : ARRAY[1..Async_Num_Bauds] OF RECORD
  396.                                                          Baud, Bits : Integer;
  397.                                                        END
  398.  
  399.                                                        = ((Baud : 110; Bits : $417),
  400.                                                        (Baud : 150; Bits : $300),
  401.                                                        (Baud : 300; Bits : $180),
  402.                                                        (Baud : 600; Bits : $0C0),
  403.                                                        (Baud : 1200; Bits : $060),
  404.                                                        (Baud : 2400; Bits : $030),
  405.                                                        (Baud : 4800; Bits : $018),
  406.                                                        (Baud : 9600; Bits : $00C));
  407.  
  408.     VAR
  409.       ComBaud, ComParm : Integer;
  410.       i : Integer;
  411.       m : Integer;
  412.  
  413.     BEGIN                               { Async_Open }
  414.  
  415.       { If port open, close it down first. }
  416.  
  417.       IF Async_Open_Flag THEN Async_Close;
  418.  
  419.       { Choose communications port }
  420.  
  421.       Async_Port := ComPort;
  422.       Async_Base := COM_Base[ComPort];
  423.       Async_Irq := COM_Irq[ComPort];
  424.  
  425.  
  426.       IF (Port[UART_IIR+Async_Base] AND $00F8) <> 0 THEN
  427.         Async_Open := False             { Serial port not installed }
  428.       ELSE
  429.         BEGIN                           { Open the port }
  430.  
  431.           { Set buffer pointers }
  432.  
  433.           Async_Buffer_Head := 0;
  434.           Async_Buffer_Tail := 0;
  435.           Async_Buffer_Overflow := False;
  436.  
  437.           {---------------------------------------------------}
  438.           {    Build the ComParams to init the UART           }
  439.           {---------------------------------------------------}
  440.  
  441.           { Set up the bits for the baud rate }
  442.  
  443.           IF BaudRate > 9600 THEN
  444.             BaudRate := 9600
  445.           ELSE IF BaudRate <= 0 THEN
  446.             BaudRate := 300;
  447.  
  448.           i := 0;
  449.  
  450.           REPEAT
  451.             i := i+1
  452.           UNTIL ((i >= Async_Num_Bauds) OR
  453.           (BaudRate = Async_Baud_Table[i].Baud));
  454.  
  455.           ComBaud := Async_Baud_Table[i].Bits;
  456.  
  457.           { Choose Parity }
  458.  
  459.           ComParm := $00;               { Assume no parity }
  460.           IF Parity IN ['E', 'e'] THEN
  461.             ComParm := $0018
  462.           ELSE IF Parity IN ['O', 'o'] THEN
  463.             ComParm := $0008;
  464.  
  465.           { Choose number of data bits }
  466.  
  467.           WordSize := WordSize-5;
  468.  
  469.           IF (WordSize < 0) OR (WordSize > 3) THEN
  470.             WordSize := 3;
  471.  
  472.           ComParm := ComParm OR WordSize;
  473.  
  474.           { Choose stop bits }
  475.  
  476.           IF StopBits = 2 THEN
  477.             ComParm := ComParm OR $0004; { default is 1 stop bit }
  478.  
  479.           DOS_Set_Intrpt(Async_Irq+8, CSeg, Ofs(Async_Isr));
  480.  
  481.           INLINE($FA);                  { disable interrupts }
  482.  
  483.           { Set the parity, datalength, stopbits and baudrate }
  484.           { Turn on Divisor Access Latch Bit first            }
  485.  
  486.           ComParm := ComParm OR $80;
  487.           Port[UART_LCR+Async_Base] := ComParm;
  488.           Port[UART_DLM+Async_Base] := Hi(ComBaud);
  489.           Port[UART_DLL+Async_Base] := Lo(ComBaud);
  490.  
  491.           { Read the RBR and reset any pending error conditions. }
  492.           { First turn off the Divisor Access Latch Bit to allow }
  493.           { access to RBR, etc.                                  }
  494.  
  495.           Port[UART_LCR+Async_Base] := Port[UART_LCR+Async_Base] AND $7F;
  496.  
  497.           { Read the Line Status Register to reset any errors }
  498.           { it indicates                                      }
  499.  
  500.           i := Port[UART_LSR+Async_Base];
  501.  
  502.           { Read the Receiver Buffer Register in case it }
  503.           { contains a character                         }
  504.  
  505.           i := Port[UART_RBR+Async_Base];
  506.  
  507.           { enable the irq on the 8259 controller }
  508.  
  509.           i := Port[I8088_IMR];         { get the interrupt mask register }
  510.           m := (1 SHL Async_Irq) XOR $00FF;
  511.  
  512.           Port[I8088_IMR] := i AND m;
  513.  
  514.           { enable the data ready interrupt on the 8250 }
  515.  
  516.           Port[UART_IER+Async_Base] := $01;
  517.  
  518.           { enable OUT2 on 8250 }
  519.  
  520.           i := Port[UART_MCR+Async_Base];
  521.           Port[UART_MCR+Async_Base] := i OR $08;
  522.  
  523.  
  524.           INLINE($FB);                  { enable interrupts }
  525.  
  526.           Async_Open := True;
  527.           Async_Open_Flag := True;
  528.  
  529.         END;
  530.  
  531.     END { Async_Open } ;
  532.  
  533.     {----------------------------------------------------------------------}
  534.     {          Async_Buffer_Check --- Check if character in buffer         }
  535.     {----------------------------------------------------------------------}
  536.  
  537.   FUNCTION Async_Buffer_Check : Boolean;
  538.  
  539.       {                                                                      }
  540.       {     Function:   Async_Buffer_Check                                   }
  541.       {                                                                      }
  542.       {     Purpose:    Check if character in buffer                         }
  543.       {                                                                      }
  544.       {     Calling Sequence:                                                }
  545.       {                                                                      }
  546.       {        Flag := Async_Buffer_Check : Boolean;                         }
  547.       {                                                                      }
  548.       {           Flag returned TRUE if character received in buffer,        }
  549.       {           Flag returned FALSE if no character received.              }
  550.       {                                                                      }
  551.       {     Calls:  None                                                     }
  552.       {                                                                      }
  553.       {     Remarks:                                                         }
  554.       {                                                                      }
  555.       {       This routine only checks if a character has been received      }
  556.       {       and thus can be read; it does NOT return the character.        }
  557.       {       Use Async_Receive to read the character.                       }
  558.       {                                                                      }
  559.  
  560.     BEGIN                               { Async_Buffer_Check }
  561.  
  562.       Async_Buffer_Check := (Async_Buffer_Head <> Async_Buffer_Tail);
  563.  
  564.     END { Async_Buffer_Check } ;
  565.  
  566.     {----------------------------------------------------------------------}
  567.     {          Async_Receive --- Return character from buffer              }
  568.     {----------------------------------------------------------------------}
  569.  
  570.   FUNCTION Async_Receive(VAR C : Char) : Boolean;
  571.  
  572.       {                                                                      }
  573.       {     Function:   Async_Receive                                        }
  574.       {                                                                      }
  575.       {     Purpose:    Retrieve character (if any) from buffer              }
  576.       {                                                                      }
  577.       {     Calling Sequence:                                                }
  578.       {                                                                      }
  579.       {        Flag := Async_Receive( Var C: Char ) : Boolean;               }
  580.       {                                                                      }
  581.       {           C --- character (if any) retrieved from buffer;            }
  582.       {                 set to CHR(0) if no character available.             }
  583.       {                                                                      }
  584.       {           Flag returned TRUE if character retrieved from buffer,     }
  585.       {           Flag returned FALSE if no character retrieved.             }
  586.       {                                                                      }
  587.       {     Calls:  None                                                     }
  588.       {                                                                      }
  589.  
  590.     BEGIN                               { Async_Receive }
  591.  
  592.       IF Async_Buffer_Head = Async_Buffer_Tail THEN
  593.         BEGIN                           { No character to retrieve }
  594.  
  595.           Async_Receive := False;
  596.           C := Chr(0);
  597.  
  598.         END                             { No character available   }
  599.  
  600.       ELSE
  601.         BEGIN                           { Character available }
  602.  
  603.           { Turn off interrupts }
  604.  
  605.           INLINE($FA);                  { CLI --- Turn off interrupts }
  606.  
  607.           { Get character from buffer }
  608.  
  609.           C := Async_Buffer[Async_Buffer_Tail];
  610.  
  611.           { Increment buffer pointer.   If past }
  612.           { end of buffer, reset to beginning.  }
  613.  
  614.           Async_Buffer_Tail := Async_Buffer_Tail+1;
  615.  
  616.           IF Async_Buffer_Tail > Async_Buffer_Max THEN
  617.             Async_Buffer_Tail := 0;
  618.  
  619.           { Decrement buffer use count }
  620.  
  621.           Async_Buffer_Used := Async_Buffer_Used-1;
  622.  
  623.           { Turn on interrupts }
  624.  
  625.           INLINE($FB);                  { STI --- Turn on interrupts }
  626.  
  627.           { Indicate character successfully retrieved }
  628.  
  629.           Async_Receive := True;
  630.  
  631.         END { Character available } ;
  632.  
  633.       C := Chr(Ord(C) AND $7F);
  634.  
  635.     END { Async_Receive } ;
  636.  
  637.     {----------------------------------------------------------------------}
  638.     {          Async_Send --- Send character over communications port      }
  639.     {----------------------------------------------------------------------}
  640.  
  641.   PROCEDURE Async_Send(C : Char);
  642.  
  643.       {                                                                      }
  644.       {     Procedure:  Async_Send                                           }
  645.       {                                                                      }
  646.       {     Purpose:    Sends character out over communications port         }
  647.       {                                                                      }
  648.       {     Calling Sequence:                                                }
  649.       {                                                                      }
  650.       {        Async_Send( C : Char );                                       }
  651.       {                                                                      }
  652.       {           C --- Character to send                                    }
  653.       {                                                                      }
  654.       {     Calls:  None                                                     }
  655.       {                                                                      }
  656.  
  657.     VAR
  658.       i : Integer;
  659.       m : Integer;
  660.       Counter : Integer;
  661.  
  662.     BEGIN                               { Async_Send }
  663.  
  664.       { Turn on OUT2, DTR, and RTS }
  665.  
  666.       Port[UART_MCR+Async_Base] := $0B;
  667.  
  668.       { Wait for CTS using Busy Wait }
  669.  
  670.       Counter := MaxInt;
  671.  
  672.       WHILE (Counter <> 0) AND
  673.       ((Port[UART_MSR+Async_Base] AND $10) = 0) DO
  674.         Counter := Counter-1;
  675.  
  676.       { Wait for Transmit Hold Register Empty (THRE) }
  677.  
  678.       IF Counter <> 0 THEN Counter := MaxInt;
  679.  
  680.       WHILE (Counter <> 0) AND
  681.       ((Port[UART_LSR+Async_Base] AND $20) = 0) DO
  682.         Counter := Counter-1;
  683.  
  684.       { Send the character if port clear }
  685.  
  686.       IF Counter <> 0 THEN
  687.         BEGIN                           { Send the Character }
  688.  
  689.           INLINE($FA);                  { CLI --- disable interrupts }
  690.  
  691.           Port[UART_THR+Async_Base] := Ord(C);
  692.  
  693.           INLINE($FB);                  { STI --- enable interrupts }
  694.  
  695.         END                             { Send the Character }
  696.  
  697.       ELSE                              { Timed Out }
  698.         WriteLn('<<< Com-port character write: TIMEOUT >>>');
  699.  
  700.     END { Async_Send } ;
  701.  
  702.     {----------------------------------------------------------------------}
  703.     {     Async_Send_String --- Send string over communications port       }
  704.     {----------------------------------------------------------------------}
  705.  
  706.   PROCEDURE Async_Send_String(S : MaxString);
  707.  
  708.       {                                                                      }
  709.       {     Procedure:  Async_Send_String                                    }
  710.       {                                                                      }
  711.       {     Purpose:    Sends string out over communications port            }
  712.       {                                                                      }
  713.       {     Calling Sequence:                                                }
  714.       {                                                                      }
  715.       {        Async_Send_String( S : AnyStr );                              }
  716.       {                                                                      }
  717.       {           S --- String to send                                       }
  718.       {                                                                      }
  719.       {     Calls:  Async_Send                                               }
  720.       {                                                                      }
  721.  
  722.     VAR
  723.       i : Integer;
  724.  
  725.     BEGIN                               { Async_Send_String }
  726.  
  727.       FOR i := 1 TO Length(S) DO BEGIN
  728.         Async_Send(S[i]);
  729.         IF (i MOD 80) = 0 THEN Delay(250);
  730.       END;
  731.     END { Async_Send_String } ;
  732.  
  733.     {----------------------------------------------------------------------}
  734.     {     Async_Purge_Buffer --- Purge communications input buffer         }
  735.     {----------------------------------------------------------------------}
  736.  
  737.   PROCEDURE Async_Purge_Buffer;
  738.  
  739.       {                                                                      }
  740.       {     Procedure:  Async_Purge_Buffer                                   }
  741.       {                                                                      }
  742.       {     Purpose:    Purges communications input buffer                   }
  743.       {                                                                      }
  744.       {     Calling Sequence:                                                }
  745.       {                                                                      }
  746.       {        Async_Purge_Buffer;                                           }
  747.       {                                                                      }
  748.       {     Calls:  Async_Receive                                            }
  749.       {                                                                      }
  750.  
  751.     VAR
  752.       C : Char;
  753.  
  754.     BEGIN                               { Async_Purge_Buffer }
  755.  
  756.       REPEAT
  757.         Delay(1);
  758.       UNTIL (NOT Async_Receive(C));
  759.  
  760.     END { Async_Purge_Buffer } ;
  761.  
  762.     {----------------------------------------------------------------------}
  763.     {      Async_CTS_On --- Check for CTS on                               }
  764.     {----------------------------------------------------------------------}
  765.  
  766.   FUNCTION Async_CTS_On : Boolean;
  767.  
  768.       {                                                                      }
  769.       {     Function:   Async_CTS_on                                         }
  770.       {                                                                      }
  771.       {     Purpose:    Looks for CTS line state                             }
  772.       {                                                                      }
  773.       {     Calling Sequence:                                                }
  774.       {                                                                      }
  775.       {        Flag := Async_CTS_On : Boolean;                               }
  776.       {                                                                      }
  777.       {           Flag is set TRUE if CTS is On, else FALSE.                 }
  778.       {                                                                      }
  779.       {     Calls:  None                                                     }
  780.       {                                                                      }
  781.  
  782.     VAR Tmp : Boolean;
  783.  
  784.     BEGIN                               { Async_CTS_On }
  785.  
  786.       Tmp := Odd(Port[UART_MSR+Async_Base] SHR 4);
  787.       Async_CTS_On := Tmp AND (NOT Async_Blocked);
  788.  
  789.     END { Async_CTS_On } ;
  790.  
  791.