home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / PAS_ALL.ZIP / TI152.ASC < prev    next >
Encoding:
Text File  |  1991-09-11  |  21.5 KB  |  661 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  10.   VERSION : A11
  11.        OS : PC-DOS, MS-DOS
  12.      DATE : August 1, 1986                               PAGE : 1/9
  13.     TITLE : INTERRUPT HANDLER
  14.  
  15.  
  16.  
  17.  
  18.   The following example routines are public domain programs that
  19.   have been uploaded to our Forum on CompuServe. As a courtesy to
  20.   our users that do not have immediate access to CompuServe,
  21.   Technical Support distributes these routines free of charge.
  22.  
  23.   However, because these routines are public domain programs, not
  24.   developed by Borland International, we are unable to provide any
  25.   technical support or assistance using these routines. If you need
  26.   assistance using these routines, or are experiencing
  27.   difficulties, we recommend that you log onto CompuServe and
  28.   request assistance from the Forum members that developed these
  29.   routines.
  30.  
  31.   DumbTerm is an example program written to demonstrate the use of
  32.   both interrupt routines and COM port communication. There are
  33.   some inline instructions that are used in the interrupt routine
  34.   that do not appear in the Turbo Pascal manual. When making your
  35.   own interrupt handlers, be sure to save all registers as has been
  36.   done in this example. Also, there is a restoration of the DS
  37.   register in the handler. When an interrupt occurs, all segment
  38.   registers are set to the code segment of the interrupt routine.
  39.   This dis-allows the use of global variables because of a
  40.   destroyed DS register. To counteract this affect, the DS is
  41.   restored via an absolute variable "segment."
  42.  
  43.   This program was written by:
  44.  
  45.   Jim McCarthy                and          Andy Batony
  46.     Technical Support                       Teleware Incorporated
  47.     Borland International
  48.   _____________________________________________________________________
  49.   ---------------------------------------------------------------------
  50.  
  51.   PROGRAM dumbterm;
  52.  
  53.     CONST
  54.       hex        : string[16] = '0123456789ABCDEF'; { Constant used to }
  55.                                             { convert decimal to hex   }
  56.       irq4       = $30;                     { Interrupt vector address }
  57.                                             { for COM1.                }
  58.       irq3       = $2C;                     { Vector for COM2.         }
  59.       eoi        = $20;                     {                          }
  60.       com1base   = $03F8;                   { Port address of COM1.    }
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  76.   VERSION : A11
  77.        OS : PC-DOS, MS-DOS
  78.      DATE : August 1, 1986                               PAGE : 2/9
  79.     TITLE : INTERRUPT HANDLER
  80.  
  81.  
  82.  
  83.  
  84.       com2base   = $02F8;                   { Port address of COM2.    }
  85.                                             { Offset to add to         }
  86.       intenreg   = 1;                       { com#base for Interrupt   }
  87.                                             { enable register          }
  88.       intidreg   = 2;                       { Interrupt id register    }
  89.       linectrl   = 3;                       { Line control register    }
  90.       modemctrl  = 4;                       { Modem control register   }
  91.       linestat   = 5;                       { Line status register     }
  92.       modemstat  = 6;                       { Modem status register    }
  93.       buffsize   = 1024;                    { Size of the ring buffer  }
  94.  
  95.     TYPE                                    { Type declarations        }
  96.       str4       = string[4];
  97.       str80      = string[80];
  98.       ratetype   = (rate300,rate1200,rate4800,rate9600);
  99.       comtype    = (com1,com2);
  100.       bytechar   = record case boolean of
  101.                      true :(o:byte);
  102.                      false:(c:char)
  103.                    end;
  104.  
  105.  
  106.       regrec     = record
  107.                      ax,bx,cx,dx,bp,di,si,ds,es,flags : integer;
  108.                    end;
  109.  
  110.     VAR
  111.       segment    : integer absolute cseg:$00A0;  { Address for storing }
  112.       intbuffer  : array [0..buffsize] of bytechar;  { DS Ring buffer  }
  113.       oldvecseg,                       { Segment of DOS set            }
  114.       oldvecoff,                       { Offset of DOS set com int.    }
  115.       head,                            { Index to the head of the      }
  116.                                        { ring buffer.                  }
  117.       tail,                            { Tail index of the ring buff   }
  118.       comport,                         { Comport address               }
  119.       i          : integer;            { Counter                       }
  120.       comp       : comtype;            { Used to specify which comport }
  121.       ch,                              { Temporary character buffer    }
  122.       kch        : char;               { Char keyed in from the key-   }
  123.                                        { board                         }
  124.       temp       : string[80];         { Temporary buffer              }
  125.       tbyte,
  126.       lbyte      : byte;
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  142.   VERSION : A11
  143.        OS : PC-DOS, MS-DOS
  144.      DATE : August 1, 1986                               PAGE : 3/9
  145.     TITLE : INTERRUPT HANDLER
  146.  
  147.  
  148.  
  149.  
  150.       showok     : boolean;
  151.       registers  : regrec;             { Registers used in DOS call    }
  152.  
  153.   {--------------------------------------------------------------------
  154.   This is the interrupt handler for the COM1 or COM2 comports. Notice the
  155.   restoration of the DS register through a move to the AX from address
  156.   CS:00A0.  The absolute variable "segment" is initialized at the beginning
  157.   of the program to contain the value of "DSEG". The inline statments should
  158.   replace the current ones  in the TURBO PASCAL Reference Manual.
  159.   --------------------------------------------------------------------}
  160.    PROCEDURE IntHandler;
  161.  
  162.       BEGIN
  163.         inline( $50          { push ax       }
  164.                /$53          { push bx       }
  165.                /$51          { push cx       }
  166.                /$52          { push dx       }    { Save all the       }
  167.                /$57          { push di       }    { registers          }
  168.                /$56          { push si       }
  169.                /$06          { push es       }
  170.                /$1E          { push ds       }
  171.                /$2E          { cs:           }
  172.                /$A1 /$A0 /$00{ mov ax, [00A0]}    { Get the Current    }
  173.                /$50          { push ax       }    { data segment       }
  174.                /$1F          { pop ds        } ); { Restore the DS     }
  175.                                                   { register           }
  176.  
  177.         tbyte := port[ comport ];            { Get the char in the port}
  178.         lbyte := port[ comport + linestat ]; { Get status of the port  }
  179.         If ( head < buffsize ) then          { Check bounds of the ring}
  180.           head := head + 1                   { buffer, and if smaller  }
  181.         else                                 { then increment by one   }
  182.           head := 0;                         { otherwise set to the    }
  183.                                              { first element           }
  184.         intbuffer[ head ].o := tbyte;        { Load the buffer w/ the  }
  185.                                              { character               }
  186.         port[$20] := $20;                    { Enable all other        }
  187.                                              { interrupts except the   }
  188.                                              { calling INT ( 0C )      }
  189.         inline( $1F          { pop ds        }
  190.                /$07          { pop es        }
  191.                /$5E          { pop si        }
  192.                /$5F          { pop di        }
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  208.   VERSION : A11
  209.        OS : PC-DOS, MS-DOS
  210.      DATE : August 1, 1986                               PAGE : 4/9
  211.     TITLE : INTERRUPT HANDLER
  212.  
  213.  
  214.  
  215.  
  216.                /$5A          { pop dx        }
  217.                /$59          { pop cx        } { Restore all registers }
  218.                /$5B          { pop bx        }
  219.                /$58          { pop ax        }
  220.                /$5D          { pop     bp    } { Reset the stack to its}
  221.                /$89 /$EC     { mov     sp,bp } { proper position       }
  222.                /$5D          { pop     bp    }
  223.                /$CF );       { iret          } { Return                }
  224.       END;
  225.   {---------------------------------------------------------------------
  226.         The procedure AskCom gets the comport to communicate through.
  227.   ---------------------------------------------------------------------}
  228.     PROCEDURE AskCom( var comp : comtype );
  229.  
  230.       VAR
  231.         ch : char;
  232.  
  233.       BEGIN
  234.         write( 'What port is the modem in ( 1 or 2 ) : ' );
  235.                                                 { Write prompt        }
  236.         Repeat
  237.           read( kbd,ch );                       { Get the character   }
  238.         Until ( ch in ['1','2'] );              { and check bounds    }
  239.         If ( ch = '1' ) then
  240.           Begin
  241.             writeln( 'COM1:' );                 { Set to COM1         }
  242.             comp := com1;
  243.           End
  244.         else
  245.           Begin
  246.             writeln( 'COM2:' );
  247.             comp := com2;                       { Set to COM2         }
  248.           End;
  249.       END;
  250.  
  251.   {--------------------------------------------------------------------
  252.   This procedure sets the baud rate of the comport to either 300, 1200, 4800,
  253.   or 9600  baud. The Divisor latches are set according to the table in the
  254.   IBM hardware technical reference manual (p.1-238 ).
  255.   --------------------------------------------------------------------}
  256.  
  257.    PROCEDURE SetRate(r:ratetype);
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  274.   VERSION : A11
  275.        OS : PC-DOS, MS-DOS
  276.      DATE : August 1, 1986                               PAGE : 5/9
  277.     TITLE : INTERRUPT HANDLER
  278.  
  279.  
  280.  
  281.  
  282.       VAR
  283.         tlcr,                          { Line control register        }
  284.         tdlmsb,                        { Divisor latch MSB            }
  285.         tdllsb    : byte;              { Divisor latch LSB            }
  286.       BEGIN
  287.         tdlmsb:=0;                     { Set DL MSB to 0 for 1200,    }
  288.                                        { 4800 and 9600 baud           }
  289.         case r of                      { Use case to check baud rate  }
  290.           rate300 :  begin             { Check for 300 baud           }
  291.                        tdlmsb:=1;      { Set DL MSB to 01             }
  292.                        tdllsb:=$80;    { Set DL LSB to 80             }
  293.                      end;              { for a total of 0180          }
  294.  
  295.           rate1200 : tdllsb:=$60;            { 1200 set LSB to 60     }
  296.           rate4800 : tdllsb:=$18;            { 4800 set LSB to 18     }
  297.           rate9600 : tdllsb:=$0c;            { 0C for 9600 baud       }
  298.  
  299.         end;
  300.         tlcr:=port[comport+linectrl];        { Get the Line control   }
  301.                                              { register               }
  302.         port[comport+linectrl]:=tlcr or $80; { Set Divisor Latch      }
  303.                                              { Access Bit in order to }
  304.         port[comport]:=tdllsb;               { access divisor latches,}
  305.                                              { then store the values  }
  306.         port[comport+1]:=tdlmsb;             { for the desired baud   }
  307.                                              { rate                   }
  308.         port[comport+linectrl]:=tlcr and $7f;{ then clear the DLAB    }
  309.                                              { in order to access to  }
  310.                                              { the receiver buffer    }
  311.       END;
  312.  
  313.   {--------------------------------------------------------------------
  314.   WhatRate is the input procedure that uses SetRate to set the correct
  315.   baud rate.
  316.   --------------------------------------------------------------------}
  317.  
  318.     PROCEDURE WhatRate;
  319.  
  320.       BEGIN
  321.         writeln;                           { Display prompt           }
  322.         write('what baud rate ([3]00,[1]200,[4]800,[9]600) ');
  323.         read(kbd,kch);                     { Read in the baud rate    }
  324.   -
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  340.   VERSION : A11
  341.        OS : PC-DOS, MS-DOS
  342.      DATE : August 1, 1986                               PAGE : 6/9
  343.     TITLE : INTERRUPT HANDLER
  344.  
  345.  
  346.  
  347.  
  348.         case kch of
  349.           '3':SetRate(rate300);           { Set the corresponding rate }
  350.           '1':SetRate(rate1200);          {             .              }
  351.           '4':SetRate(rate4800);          {             .              }
  352.           '9':SetRate(rate9600);          {             .              }
  353.         end;
  354.         writeln(kch);
  355.       END;
  356.   {--------------------------------------------------------------------
  357.   The procedure IntOn sets up the interrupt handler vectors, and
  358.   communication protocol.
  359.   --------------------------------------------------------------------}
  360.  
  361.     PROCEDURE IntOn(com:comtype);
  362.  
  363.       CONST
  364.         bits5=0;
  365.         bits6=1;
  366.         bits7=2;
  367.  
  368.  
  369.         bits8=3;
  370.         stopbit1=0;                         { These are constants used }
  371.         stopbit2=4;                         { to define parity, stop   }
  372.         noparity=0;                         { bits, data bits, etc.    }
  373.         parity=8;
  374.         evenparity=16;
  375.         dtrtrue=1;
  376.         rtstrue=2;
  377.         bit3true=8;
  378.  
  379.       VAR
  380.         tbyte   : byte;                     { Temporary byte buffer    }
  381.         i       : integer;                  { counter                  }
  382.  
  383.       BEGIN
  384.         head:=0;                            { Initialize the ring      }
  385.         tail:=0;                            { buffer indexes           }
  386.         case com of
  387.           com1:comport:=com1base;           { Set the com port to      }
  388.                                             { talk to                  }
  389.           com2:comport:=com2base;
  390.         end;
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  406.   VERSION : A11
  407.        OS : PC-DOS, MS-DOS
  408.      DATE : August 1, 1986                               PAGE : 7/9
  409.     TITLE : INTERRUPT HANDLER
  410.  
  411.  
  412.  
  413.  
  414.         tbyte := port[ comport ];           { Read the ports to clear  }
  415.         tbyte := port[ comport + linestat ];{ any error conditions     }
  416.         WhatRate;                           { Get the baud rate        }
  417.         port[ comport + linectrl ] := bits7 + stopbit1 + noparity;
  418.                                             { Set the protocall        }
  419.         port[ comport + modemctrl ] := dtrtrue + rtstrue + bit3true;
  420.         port[ comport + intenreg ] := 1;    { Enable com port          }
  421.         tbyte := port[$21];                 { interrupts               }
  422.         with registers do
  423.           begin
  424.             ax:=$2500;                      { Load the function number }
  425.                                             { for redefining an        }
  426.                                             { interrupt                }
  427.             ds:=cseg;                       { Get and set the segment  }
  428.            dx:=ofs(IntHandler);            { and offset of the handler}
  429.           end;
  430.         case com of
  431.           com1: begin
  432.                   oldvecoff:=memw[0000:irq4];   { Save the segment and }
  433.                   oldvecseg:=memw[0000:irq4+2]; { offset of the DOS    }
  434.                                                 { interrupt handler    }
  435.                   registers.ax:=registers.ax+$0c;
  436.                                              { Use the COM1: interrupt }
  437.                   intr($21,registers);          { Call DOS to reset    }
  438.  
  439.  
  440.                   port[$21]:=tbyte and $ef;     { INT 0C               }
  441.                 end;
  442.           com2: begin
  443.                   oldvecoff:=memw[0000:irq3];   { Same as above        }
  444.                   oldvecseg:=memw[0000:irq3+2]; { Same as above        }
  445.                   registers.ax:=registers.ax+$0b;
  446.                                              { Use the COM2: interrupt }
  447.                   intr($21,registers);          { Call DOS             }
  448.                   port[$21]:=tbyte and $f7;     {                      }
  449.                 end;
  450.         end;
  451.         inline($fb);                            { Enable interrupts    }
  452.       END;
  453.  
  454.   {---------------------------------------------------------------------
  455.   This procedure restores the original system values to what they were before
  456.   the interrupt handler was set into action.
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  472.   VERSION : A11
  473.        OS : PC-DOS, MS-DOS
  474.      DATE : August 1, 1986                               PAGE : 8/9
  475.     TITLE : INTERRUPT HANDLER
  476.  
  477.  
  478.  
  479.  
  480.   ---------------------------------------------------------------------}
  481.  
  482.     PROCEDURE IntOff;
  483.  
  484.       VAR
  485.         tbyte:byte;
  486.  
  487.       BEGIN
  488.         inline($FA);  { CLI }                 { Disable interrupts     }
  489.         tbyte:=port[$21];                     {                        }
  490.         port[comport+intenreg]:=0;            { Disable COM interrupts }
  491.         If comport=$3f8 then                  { If using COM1: then    }
  492.           begin
  493.             port[$21]:=tbyte or $10;          {                        }
  494.             memw[0000:irq4]:=oldvecoff;       { Restore the DOS        }
  495.             memw[0000:irq4+2]:=oldvecseg;     { interrupt handler      }
  496.           end
  497.         else
  498.           begin
  499.             memw[0000:irq3]:=oldvecoff;         { Restore the DOS   }
  500.             memw[0000:irq3+2]:=oldvecseg;       { interrupt handler }
  501.             port[$21]:=tbyte or $08;            {                   }
  502.           end;e
  503.       END;
  504.   {------------------------------------------------------------------
  505.   If the ring buffer indexes are not equal then ReadCom returns the char from
  506.   either the COM1: or COM2: port. The character is read from the ring buffer
  507.   and is stored in the FUNCTION result.
  508.   -------------------------------------------------------------------}
  509.  
  510.     FUNCTION ReadCom : char;
  511.  
  512.       BEGIN
  513.         If ( head <> tail ) then           { Check for ring buffer  }
  514.           begin                            { character              }
  515.             If ( tail < buffsize ) then    { Check the limits of    }
  516.               tail := tail + 1             { the ring and set tail  }
  517.             else                           { accordingly            }
  518.               tail := 0;
  519.             ReadCom := intbuffer[tail].c;  { Get the character      }
  520.           end;
  521.       END;
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  538.   VERSION : A11
  539.        OS : PC-DOS, MS-DOS
  540.      DATE : August 1, 1986                               PAGE : 9/9
  541.     TITLE : INTERRUPT HANDLER
  542.  
  543.  
  544.  
  545.  
  546.   {------------------------------------------------------------------
  547.   This procedure outputs directly to the communications port the byte
  548.   equivilent of the character to be sent.
  549.   ------------------------------------------------------------------}
  550.  
  551.     PROCEDURE WriteCom( ch : char );
  552.  
  553.       VAR
  554.         tbyte:byte;
  555.  
  556.       BEGIN
  557.         tbyte:=ord(ch);                { Change to byte format      }
  558.         port[comport]:=tbyte;          { Output the character       }
  559.       END;
  560.   {------------------------------------------------------------------
  561.   When the interrupt routine is called because of a com port interrupt the
  562.   head index is incremented by one, but does not increment the tail index.
  563.   This causes the two indexes to be unequal, and ModemInput to become true.
  564.   ------------------------------------------------------------------}
  565.  
  566.   FUNCTION ModemInput:boolean;
  567.  
  568.     begin
  569.       ModemInput:=(head<>tail);
  570.       end;
  571.  
  572.   BEGIN
  573.     segment := dseg;         { segment is an absolute variable used  }
  574.                              { by the interrupt routine to restore   }
  575.                              { the DS register to point to the DSEG  }
  576.     AskCom( comp );          { Get the com port to use               }
  577.     IntOn( comp );           { Set up the interrupt routine          }
  578.  
  579.     ch:=' ';                 { Initialize ch for the loop            }
  580.     Repeat
  581.       If keypressed then     { If a key is pressed on the keyboard   }
  582.         begin
  583.           read(kbd,kch);     { then the program reads it in and      }
  584.           kch := Upcase(kch);
  585.           write( kch );
  586.           If ( kch = chr(13)) then writeln;
  587.                              { checks if the program should be ended }
  588.           WriteCom(kch);     { Write the character to the com port   }
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  604.   VERSION : A11
  605.        OS : PC-DOS, MS-DOS
  606.      DATE : August 1, 1986                              PAGE : 10/9
  607.     TITLE : INTERRUPT HANDLER
  608.  
  609.  
  610.  
  611.  
  612.         end;
  613.       If ModemInput then     { If something was placed in the ring   }
  614.         begin                { buffer then                           }
  615.           write('[');
  616.           ch:=ReadCom;       { it is read in and printed to the      }
  617.           write(ch);         { screen                                }
  618.           If ch=chr(13) then writeln;
  619.           write(']');
  620.         end;
  621.     Until kch=chr(27);       { This loops ends when <esc> is hit     }
  622.     IntOff;                  { Restore the environment               }
  623.   END.        { Main program }
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.