home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / ASYNCTRM.ZIP / ASYNCTRM.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1988-02-11  |  16.5 KB  |  360 lines

  1. PROGRAM tp_async;
  2.  
  3. uses crt,dos;
  4.  
  5. procedure cli; inline($fa);
  6. procedure sti; inline($fb);
  7.  
  8. {----------------------------------------------------------------------------
  9.       DumbTerm is an example program written to demonstrate the use of both
  10.  interrupt routines and com port communication.
  11.  
  12. Upgraded to Turbo Pascal 4.0                   written by,
  13.   By Kevin Nixon                                  Jim McCarthy
  14.   HB Design Group                                 Technical Support
  15. Added 2400 baud support                           Borland International
  16.  
  17.                                                 and
  18.                                                   Andy Batony
  19.                                                   Teleware Incorporated
  20.  
  21. -----------------------------------------------------------------------------}
  22.  
  23.  
  24.  
  25.   const
  26.     hex        : string[16] = '0123456789ABCDEF'; { constant used to convert }
  27.                                                   { decimal to hex           }
  28.     com1_intr  = $0c;                         { interrupt number of com1     }
  29.     com2_intr  = $0b;                         { interrupt number of com2?    }
  30.     irq4       = $30;                         { Interrupt vector address for }
  31.                                               { COM1.                        }
  32.     irq3       = $2C;                         { Vector for COM2.             }
  33.     eoi        = $20;                         {                              }
  34.     com1base   = $03F8;                       { Port address of COM1.        }
  35.     com2base   = $02F8;                       { Port address of COM2.        }
  36.                                               { Offset to add to com#base for}
  37.     intenreg   = 1;                           {   Interrupt enable register  }
  38.     intidreg   = 2;                           {   Interrupt id register      }
  39.     linectrl   = 3;                           {   Line control register      }
  40.     modemctrl  = 4;                           {   Modem control register     }
  41.     linestat   = 5;                           {   Line status register       }
  42.     modemstat  = 6;                           {   Modem status register      }
  43.     buffsize   = 1024;                        { Size of the ring buffer      }
  44.  
  45.   type                                        { type declarations            }
  46.     str4       = string[4];
  47.     str80      = string[80];
  48.     ratetype   = (rate300,rate1200,rate2400,rate4800,rate9600);
  49.     comtype    = (com1,com2);
  50.     bytechar   = record case boolean of
  51.                    true :(o:byte);
  52.                    false:(c:char)
  53.                  end;
  54.  
  55.   var
  56.     intbuffer    : array [0..buffsize] of bytechar;    { Ring buffer         }
  57.     oldvecaddr : pointer;                     { Address of DOS set           }
  58.                                               { Offset of DOS set com int.   }
  59.     head,                                     { Index to the head of the     }
  60.                                               { ring buffer.                 }
  61.     tail,                                     { Tail index of the ring buff  }
  62.     comport,                                  { Comport address              }
  63.     i            : integer;                   { Counter                      }
  64.     comp         : comtype;                   { used to specify which comport}
  65.     ch,                                       { Temperary character buffer   }
  66.     kch          : char;                      { Char keyed in from the key-  }
  67.                                               { board                        }
  68.     temp         : string[80];                { Temperary buffer             }
  69.     tbyte,
  70.     lbyte        : byte;
  71.     showok       : boolean;
  72.     reg_set      : registers;                 { Registers used in DOS call   }
  73.  
  74. {----------------------------------------------------------------------------
  75.       This is the interrupt handler for the COM1 or COM2 comports.  Notice
  76.  the restoration of the DS register through a move to the AX from address
  77.  CS:00A0.  The absolute variable "segment" is initialized at the begining
  78.  of the program to contain the value of "DSEG".  The inline statments should
  79.  replace the current ones in the Turbo reference manual.
  80. ----------------------------------------------------------------------------}
  81.  
  82.   procedure IntHandler;
  83.   interrupt;
  84.     begin
  85.  
  86.       inline( $50            { push ax        }
  87.              /$53            { push bx        }
  88.              /$51            { push cx        }
  89.              /$52            { push dx        }    { Save all the registers }
  90.              /$57            { push di        }
  91.              /$56            { push si        }
  92.              /$06            { push es        }
  93.              /$1E            { push ds        });
  94.  
  95.       tbyte := port[ comport ];               { Get the character in the port}
  96.       lbyte := port[ comport + linestat ];    { Get the status of the port   }
  97.       If ( head < buffsize ) then             { Check bounds of the ring     }
  98.         head := head + 1                      { buffer,  and if smaller then }
  99.       else                                    { increment by one otherwise   }
  100.         head := 0;                            { set to the first element     }
  101.       intbuffer[ head ].o := tbyte;           { Load the buffer w/ the char. }
  102.       port[$20] := $20;                       {                              }
  103.       inline( $1F            { pop ds         }
  104.              /$07            { pop es         }
  105.              /$5E            { pop si         }
  106.              /$5F            { pop di         }
  107.              /$5A            { pop dx         }
  108.              /$59            { pop cx         }   { Restore all reg_set  }
  109.              /$5B            { pop bx         }
  110.              /$58            { pop ax         } )
  111.  
  112. (*
  113.              /$5D            { pop     bp     }   { Reset the stack to its }
  114.              /$89 /$EC       { mov     sp,bp  }   { proper position        }
  115.              /$5D            { pop     bp     }
  116.              /$CF );         { iret           }   { Return                 } *)
  117.     end;
  118.  
  119.  
  120. {-----------------------------------------------------------------------------
  121.       The procedure AskCom gets the comport to comunicate through.
  122. -----------------------------------------------------------------------------}
  123.  
  124.   procedure AskCom( var comp : comtype );
  125.  
  126.     var
  127.       ch : char;
  128.  
  129.     begin
  130.       write( 'what port is the modem in ( 1 or 2 ) : ' );  { write prompt }
  131.       Repeat
  132.         ch := readkey;                        { Get the character and        }
  133.       until ( ch in ['1','2'] );              { check bounds                 }
  134.       If ( ch = '1' ) then
  135.         begin
  136.           writeln( 'COM1:' );                 { Set to COM1                  }
  137.           comp := com1;
  138.         end
  139.       else
  140.         begin
  141.           writeln( 'COM2:' );
  142.           comp := com2;                       { Set to COM2                  }
  143.         end;
  144.     end;
  145.  
  146. {-----------------------------------------------------------------------------
  147.       This procedure sets the baud rate of the comport to either 300, 1200,
  148.  2400, 4800, or 9600 baud.  The Divisor latches are set according to the table
  149.  in the IBM hardware technical reference manual ( p. 1-238 ).
  150. -----------------------------------------------------------------------------}
  151.  
  152.   procedure SetRate(r:ratetype);
  153.  
  154.     var
  155.       tlcr,                                   { Line control register        }
  156.       tdlmsb,                                 { Divisor latch MSB            }
  157.       tdllsb    : byte;                       { Divisor latch LSB            }
  158.  
  159.     begin
  160.  
  161.       tdlmsb:=0;                              { Set DL MSB to 0 for 1200,    }
  162.                                               { 4800 and 9600 baud           }
  163.       case r of                               { use case to check baud rate  }
  164.         rate300 :  begin                      { Check for 300 baud           }
  165.                      tdlmsb:=1;               { Set DL MSB to 01             }
  166.                      tdllsb:=$80;             { Set DL LSB to 80             }
  167.                    end;
  168.         rate1200 : tdllsb:=$60;               { 1200 set LSB to 60           }
  169.         rate2400 : tdllsb:=$30;               { 2400 set LSB to 30           }
  170.         rate4800 : tdllsb:=$18;               { 4800 set LSB to 18           }
  171.         rate9600 : tdllsb:=$0c;               { 0C for 9600 baud             }
  172.       end;
  173.  
  174.       tlcr:=port[comport+linectrl];           { Get the Line control register}
  175.       port[comport + linectrl] := tlcr or $80;{ Set Divisor Latch Access Bit }
  176.       port[comport]:=tdllsb;                  { in order to access divisor   }
  177.       port[comport+1]:=tdlmsb;                { latches, then store the      }
  178.                                               { values for the desired baud  }
  179.                                               { rate                         }
  180.       port[comport+linectrl]:=tlcr and $7f;   { then clear the DLAB in order }
  181.                                               { to access to the receiver    }
  182.                                               { buffer                       }
  183.     end;
  184.  
  185. {----------------------------------------------------------------------------
  186.       whatRate is the input procedure that uses SetRate to set the correct
  187.  baud rate.
  188. ----------------------------------------------------------------------------}
  189.  
  190.   procedure whatRate;
  191.  
  192.     begin
  193.       writeln;                                { Display prompt             }
  194.       write('what baud rate ([3]00,[1]200,[2]400,[4]800,[9]600) ');
  195.       kch := readkey;                         { Read in the baud rate      }
  196.       case kch of
  197.         '3':SetRate(rate300);                 { Set the corrisponding rate }
  198.         '1':SetRate(rate1200);                {             .              }
  199.         '2':SetRate(rate2400);                {             .              }
  200.         '4':SetRate(rate4800);                {             .              }
  201.         '9':SetRate(rate9600);                {             .              }
  202.       end;
  203.       writeln(kch);
  204.     end;
  205.  
  206. {-------------------------------------------------------------------------
  207.       The procedure IntOn sets up the interrupt handler vectors,  and
  208.  communication protocal.
  209. -------------------------------------------------------------------------}
  210.  
  211.   procedure IntOn(com:comtype);
  212.  
  213.     const
  214.       bits5=0;
  215.       bits6=1;
  216.       bits7=2;
  217.       bits8=3;
  218.       stopbit1=0;                             { These are constants used     }
  219.       stopbit2=4;                             { to define parity, stop bits, }
  220.       noparity=0;                             { data bits, etc.              }
  221.       parity=8;
  222.       evenparity=16;
  223.       dtrtrue=1;
  224.       rtstrue=2;
  225.       bit3true=8;
  226.  
  227.     var
  228.       tbyte   : byte;                         { Temporary byte buffer        }
  229.       i       : integer;                      { counter                      }
  230.  
  231.     begin
  232.       head:=0;                                { Initialize the ring buffer   }
  233.       tail:=0;                                { indexes                      }
  234.       case com of
  235. com1:    comport:=com1base;                   { Set the com port to talk to  }
  236. com2:    comport:=com2base;
  237.       end;
  238.       tbyte := port[ comport ];               { Read the ports to clear any  }
  239.       tbyte := port[ comport + linestat ];    { error conditions             }
  240.       whatRate;                               { Get the baud rate            }
  241.       port[ comport + linectrl ] := bits8 + stopbit1 + noparity;
  242.                                               { Set the protocall            }
  243.       port[ comport + modemctrl ] := dtrtrue + rtstrue + bit3true;
  244.       port[ comport + intenreg ] := 1;        { Enable com port interrupts   }
  245.       tbyte := port[$21];                     {                              }
  246.       case com of
  247. com1:    begin
  248.             getintvec(com1_intr,OldVecAddr);  { Save the segment and offset  }
  249.             setintvec(com1_intr,@IntHandler);
  250.             port[$21]:=tbyte and $ef;         {                              }
  251.          end;
  252.  
  253. com2:    begin
  254.             getintvec(com2_intr,OldVecAddr);   { Save the segment and offset  }
  255.             setintvec(com2_intr,@IntHandler);
  256.             port[$21]:=tbyte and $f7;          {                              }
  257.          end
  258.       end;
  259.       sti;                                     { Enable interrupts            }
  260.     end;
  261.  
  262. {-----------------------------------------------------------------------------
  263.       This procedure restores the original system values to what they
  264.  were before the interrupt handler was set into action.
  265. -----------------------------------------------------------------------------}
  266.  
  267.   procedure IntOff;
  268.  
  269.     var
  270.       tbyte:byte;
  271.  
  272.     begin
  273.       cli;                                    { Disable interrupts           }
  274.       tbyte:=port[$21];                       {                              }
  275.       port[comport+intenreg]:=0;              { Disable COM interrupts       }
  276.       If comport=$3f8 then                    { If using COM1: then          }
  277.         begin
  278.           setintvec(com1_intr, oldvecaddr);
  279.           port[$21]:=tbyte or $10;            {                              }
  280.         end
  281.       else
  282.         begin
  283.           setintvec(com2_intr, oldvecaddr);
  284.           port[$21]:=tbyte or $08;            {                              }
  285.         end;
  286.     end;
  287.  
  288. {-----------------------------------------------------------------------------
  289.       If the ring buffer indexes are not equal then ReadCom returns the
  290.  char from either the COM1: or COM2: port.  The character is read from the
  291.  ring buffer and is stored in the function result.
  292. -----------------------------------------------------------------------------}
  293.  
  294.   function ReadCom : char;
  295.  
  296.     begin
  297.       If ( head <> tail ) then           { Check for ring buffer character   }
  298.         begin
  299.           If ( tail < buffsize ) then    { Check the limits of the ring      }
  300.             tail := tail + 1             { and set tail accordingly          }
  301.           else
  302.             tail := 0;
  303.           ReadCom := intbuffer[tail].c;  { Get the character                 }
  304.         end;
  305.     end;
  306.  
  307. {----------------------------------------------------------------------------
  308.       This procedure outputs directly to the communications port the byte
  309.  equivilent of the character to be sent.
  310. ----------------------------------------------------------------------------}
  311.  
  312.   procedure writeCom( ch : char );
  313.  
  314.     var
  315.       tbyte:byte;
  316.  
  317.     begin
  318.       tbyte:=ord(ch);                { Change to byte format                }
  319.       port[comport]:=tbyte;          { Output the character                 }
  320.     end;
  321.  
  322. {---------------------------------------------------------------------------
  323.       when the interrupt routine is called because of a com port interrupt
  324.  the head index is incremented by one,  but does not increment the tail
  325.  index.  This causes the two indexes to be unequal,  and ModemInput to
  326.  become true.
  327. ---------------------------------------------------------------------------}
  328.  
  329.   function ModemInput:boolean;
  330.  
  331.     begin
  332.       ModemInput:=(head<>tail);
  333.     end;
  334.  
  335. begin
  336.   writeln('Escape to exit');
  337.   writeln('Warning ... Com2 support is shakey, I wasn''t able to test it.');
  338.   writeln('Written by Jim McCarthy and Andy Batony');
  339.   writeln('Upgraded to TP 4.0 by Kevin A. Nixon, Foundation''s Edge - 714-640-1515');
  340.  
  341.  
  342.   AskCom( comp );                 { Get the com port to use               }
  343.   IntOn( comp );                  { Set up the interrupt routine          }
  344.   ch:=' ';                        { Initialize ch for the loop            }
  345.   Repeat
  346.     If keypressed then            { If a key is pressed on the keyboard   }
  347.       begin
  348.         kch := readkey;           { then the program reads it in and      }
  349.                                   { checks if the program should be ended }
  350.         writeCom(kch);            { write the character to the com port   }
  351.       end;
  352.     If ModemInput then            { If something was placed in the ring   }
  353.       begin                       { buffer then                           }
  354.         ch:=ReadCom;              { it is read in and printed to the      }
  355.         write(ch);                { screen                                }
  356.       end;
  357.   until kch=chr(27);              { This loops ends when <esc> is hit     }
  358.   IntOff;                         { Restore the enviornment               }
  359. end.       { Main program }
  360.