home *** CD-ROM | disk | FTP | other *** search
- PROGRAM tp_async;
-
- uses crt,dos;
-
- procedure cli; inline($fa);
- procedure sti; inline($fb);
-
- {----------------------------------------------------------------------------
- DumbTerm is an example program written to demonstrate the use of both
- interrupt routines and com port communication.
-
- Upgraded to Turbo Pascal 4.0 written by,
- By Kevin Nixon Jim McCarthy
- HB Design Group Technical Support
- Added 2400 baud support Borland International
-
- and
- Andy Batony
- Teleware Incorporated
-
- -----------------------------------------------------------------------------}
-
-
-
- const
- hex : string[16] = '0123456789ABCDEF'; { constant used to convert }
- { decimal to hex }
- com1_intr = $0c; { interrupt number of com1 }
- com2_intr = $0b; { interrupt number of com2? }
- irq4 = $30; { Interrupt vector address for }
- { COM1. }
- irq3 = $2C; { Vector for COM2. }
- eoi = $20; { }
- com1base = $03F8; { Port address of COM1. }
- com2base = $02F8; { Port address of COM2. }
- { Offset to add to com#base for}
- intenreg = 1; { Interrupt enable register }
- intidreg = 2; { Interrupt id register }
- linectrl = 3; { Line control register }
- modemctrl = 4; { Modem control register }
- linestat = 5; { Line status register }
- modemstat = 6; { Modem status register }
- buffsize = 1024; { Size of the ring buffer }
-
- type { type declarations }
- str4 = string[4];
- str80 = string[80];
- ratetype = (rate300,rate1200,rate2400,rate4800,rate9600);
- comtype = (com1,com2);
- bytechar = record case boolean of
- true :(o:byte);
- false:(c:char)
- end;
-
- var
- intbuffer : array [0..buffsize] of bytechar; { Ring buffer }
- oldvecaddr : pointer; { Address of DOS set }
- { Offset of DOS set com int. }
- head, { Index to the head of the }
- { ring buffer. }
- tail, { Tail index of the ring buff }
- comport, { Comport address }
- i : integer; { Counter }
- comp : comtype; { used to specify which comport}
- ch, { Temperary character buffer }
- kch : char; { Char keyed in from the key- }
- { board }
- temp : string[80]; { Temperary buffer }
- tbyte,
- lbyte : byte;
- showok : boolean;
- reg_set : registers; { Registers used in DOS call }
-
- {----------------------------------------------------------------------------
- This is the interrupt handler for the COM1 or COM2 comports. Notice
- the restoration of the DS register through a move to the AX from address
- CS:00A0. The absolute variable "segment" is initialized at the begining
- of the program to contain the value of "DSEG". The inline statments should
- replace the current ones in the Turbo reference manual.
- ----------------------------------------------------------------------------}
-
- procedure IntHandler;
- interrupt;
- begin
-
- inline( $50 { push ax }
- /$53 { push bx }
- /$51 { push cx }
- /$52 { push dx } { Save all the registers }
- /$57 { push di }
- /$56 { push si }
- /$06 { push es }
- /$1E { push ds });
-
- tbyte := port[ comport ]; { Get the character in the port}
- lbyte := port[ comport + linestat ]; { Get the status of the port }
- If ( head < buffsize ) then { Check bounds of the ring }
- head := head + 1 { buffer, and if smaller then }
- else { increment by one otherwise }
- head := 0; { set to the first element }
- intbuffer[ head ].o := tbyte; { Load the buffer w/ the char. }
- port[$20] := $20; { }
- inline( $1F { pop ds }
- /$07 { pop es }
- /$5E { pop si }
- /$5F { pop di }
- /$5A { pop dx }
- /$59 { pop cx } { Restore all reg_set }
- /$5B { pop bx }
- /$58 { pop ax } )
-
- (*
- /$5D { pop bp } { Reset the stack to its }
- /$89 /$EC { mov sp,bp } { proper position }
- /$5D { pop bp }
- /$CF ); { iret } { Return } *)
- end;
-
-
- {-----------------------------------------------------------------------------
- The procedure AskCom gets the comport to comunicate through.
- -----------------------------------------------------------------------------}
-
- procedure AskCom( var comp : comtype );
-
- var
- ch : char;
-
- begin
- write( 'what port is the modem in ( 1 or 2 ) : ' ); { write prompt }
- Repeat
- ch := readkey; { Get the character and }
- until ( ch in ['1','2'] ); { check bounds }
- If ( ch = '1' ) then
- begin
- writeln( 'COM1:' ); { Set to COM1 }
- comp := com1;
- end
- else
- begin
- writeln( 'COM2:' );
- comp := com2; { Set to COM2 }
- end;
- end;
-
- {-----------------------------------------------------------------------------
- This procedure sets the baud rate of the comport to either 300, 1200,
- 2400, 4800, or 9600 baud. The Divisor latches are set according to the table
- in the IBM hardware technical reference manual ( p. 1-238 ).
- -----------------------------------------------------------------------------}
-
- procedure SetRate(r:ratetype);
-
- var
- tlcr, { Line control register }
- tdlmsb, { Divisor latch MSB }
- tdllsb : byte; { Divisor latch LSB }
-
- begin
-
- tdlmsb:=0; { Set DL MSB to 0 for 1200, }
- { 4800 and 9600 baud }
- case r of { use case to check baud rate }
- rate300 : begin { Check for 300 baud }
- tdlmsb:=1; { Set DL MSB to 01 }
- tdllsb:=$80; { Set DL LSB to 80 }
- end;
- rate1200 : tdllsb:=$60; { 1200 set LSB to 60 }
- rate2400 : tdllsb:=$30; { 2400 set LSB to 30 }
- rate4800 : tdllsb:=$18; { 4800 set LSB to 18 }
- rate9600 : tdllsb:=$0c; { 0C for 9600 baud }
- end;
-
- tlcr:=port[comport+linectrl]; { Get the Line control register}
- port[comport + linectrl] := tlcr or $80;{ Set Divisor Latch Access Bit }
- port[comport]:=tdllsb; { in order to access divisor }
- port[comport+1]:=tdlmsb; { latches, then store the }
- { values for the desired baud }
- { rate }
- port[comport+linectrl]:=tlcr and $7f; { then clear the DLAB in order }
- { to access to the receiver }
- { buffer }
- end;
-
- {----------------------------------------------------------------------------
- whatRate is the input procedure that uses SetRate to set the correct
- baud rate.
- ----------------------------------------------------------------------------}
-
- procedure whatRate;
-
- begin
- writeln; { Display prompt }
- write('what baud rate ([3]00,[1]200,[2]400,[4]800,[9]600) ');
- kch := readkey; { Read in the baud rate }
- case kch of
- '3':SetRate(rate300); { Set the corrisponding rate }
- '1':SetRate(rate1200); { . }
- '2':SetRate(rate2400); { . }
- '4':SetRate(rate4800); { . }
- '9':SetRate(rate9600); { . }
- end;
- writeln(kch);
- end;
-
- {-------------------------------------------------------------------------
- The procedure IntOn sets up the interrupt handler vectors, and
- communication protocal.
- -------------------------------------------------------------------------}
-
- procedure IntOn(com:comtype);
-
- const
- bits5=0;
- bits6=1;
- bits7=2;
- bits8=3;
- stopbit1=0; { These are constants used }
- stopbit2=4; { to define parity, stop bits, }
- noparity=0; { data bits, etc. }
- parity=8;
- evenparity=16;
- dtrtrue=1;
- rtstrue=2;
- bit3true=8;
-
- var
- tbyte : byte; { Temporary byte buffer }
- i : integer; { counter }
-
- begin
- head:=0; { Initialize the ring buffer }
- tail:=0; { indexes }
- case com of
- com1: comport:=com1base; { Set the com port to talk to }
- com2: comport:=com2base;
- end;
- tbyte := port[ comport ]; { Read the ports to clear any }
- tbyte := port[ comport + linestat ]; { error conditions }
- whatRate; { Get the baud rate }
- port[ comport + linectrl ] := bits8 + stopbit1 + noparity;
- { Set the protocall }
- port[ comport + modemctrl ] := dtrtrue + rtstrue + bit3true;
- port[ comport + intenreg ] := 1; { Enable com port interrupts }
- tbyte := port[$21]; { }
- case com of
- com1: begin
- getintvec(com1_intr,OldVecAddr); { Save the segment and offset }
- setintvec(com1_intr,@IntHandler);
- port[$21]:=tbyte and $ef; { }
- end;
-
- com2: begin
- getintvec(com2_intr,OldVecAddr); { Save the segment and offset }
- setintvec(com2_intr,@IntHandler);
- port[$21]:=tbyte and $f7; { }
- end
- end;
- sti; { Enable interrupts }
- end;
-
- {-----------------------------------------------------------------------------
- This procedure restores the original system values to what they
- were before the interrupt handler was set into action.
- -----------------------------------------------------------------------------}
-
- procedure IntOff;
-
- var
- tbyte:byte;
-
- begin
- cli; { Disable interrupts }
- tbyte:=port[$21]; { }
- port[comport+intenreg]:=0; { Disable COM interrupts }
- If comport=$3f8 then { If using COM1: then }
- begin
- setintvec(com1_intr, oldvecaddr);
- port[$21]:=tbyte or $10; { }
- end
- else
- begin
- setintvec(com2_intr, oldvecaddr);
- port[$21]:=tbyte or $08; { }
- end;
- end;
-
- {-----------------------------------------------------------------------------
- If the ring buffer indexes are not equal then ReadCom returns the
- char from either the COM1: or COM2: port. The character is read from the
- ring buffer and is stored in the function result.
- -----------------------------------------------------------------------------}
-
- function ReadCom : char;
-
- begin
- If ( head <> tail ) then { Check for ring buffer character }
- begin
- If ( tail < buffsize ) then { Check the limits of the ring }
- tail := tail + 1 { and set tail accordingly }
- else
- tail := 0;
- ReadCom := intbuffer[tail].c; { Get the character }
- end;
- end;
-
- {----------------------------------------------------------------------------
- This procedure outputs directly to the communications port the byte
- equivilent of the character to be sent.
- ----------------------------------------------------------------------------}
-
- procedure writeCom( ch : char );
-
- var
- tbyte:byte;
-
- begin
- tbyte:=ord(ch); { Change to byte format }
- port[comport]:=tbyte; { Output the character }
- end;
-
- {---------------------------------------------------------------------------
- when the interrupt routine is called because of a com port interrupt
- the head index is incremented by one, but does not increment the tail
- index. This causes the two indexes to be unequal, and ModemInput to
- become true.
- ---------------------------------------------------------------------------}
-
- function ModemInput:boolean;
-
- begin
- ModemInput:=(head<>tail);
- end;
-
- begin
- writeln('Escape to exit');
- writeln('Warning ... Com2 support is shakey, I wasn''t able to test it.');
- writeln('Written by Jim McCarthy and Andy Batony');
- writeln('Upgraded to TP 4.0 by Kevin A. Nixon, Foundation''s Edge - 714-640-1515');
-
-
- AskCom( comp ); { Get the com port to use }
- IntOn( comp ); { Set up the interrupt routine }
- ch:=' '; { Initialize ch for the loop }
- Repeat
- If keypressed then { If a key is pressed on the keyboard }
- begin
- kch := readkey; { then the program reads it in and }
- { checks if the program should be ended }
- writeCom(kch); { write the character to the com port }
- end;
- If ModemInput then { If something was placed in the ring }
- begin { buffer then }
- ch:=ReadCom; { it is read in and printed to the }
- write(ch); { screen }
- end;
- until kch=chr(27); { This loops ends when <esc> is hit }
- IntOff; { Restore the enviornment }
- end. { Main program }