home *** CD-ROM | disk | FTP | other *** search
- {--------------------------------------------------------------}
- { JTERM }
- { }
- { by Jeff Duntemann }
- { Turbo Pascal V5.0 }
- { Last update 7/24/88 }
- { }
- { This is an interrupt-driven "dumb terminal" program for the }
- { PC. It illustrates the use of Turbo Pascal's INTERRUPT }
- { procedures, and in a lesser fashion the use of serial port }
- { hardware. It is currently hardwired to COM1 for simplicity's}
- { sake. }
- { }
- { From: COMPLETE TURBO PASCAL 5.0 by Jeff Duntemann }
- { Scott, Foresman & Co., Inc. 1988 ISBN 0-673-38355-5 }
- {--------------------------------------------------------------}
-
-
- PROGRAM JTerm;
-
- USES DOS,CRT;
-
-
- CONST
- COM1INT = 12; { Vector # for COM1: (IRQ4) }
-
- { 8250 control registers, masks, etc. }
- RBR = $3F8; { 8250 Receive Buffer Register }
- THR = $3F8; { 8250 Transmit Holding Register }
- LCR = $3FB; { 8250 Line Control Register }
- IER = $3F9; { 8250 Interrupt Enable Register }
- MCR = $3FC; { 8250 Modem Control Register }
- LSR = $3FD; { 8250 Line Status Register }
- DLL = $3F8; { 8250 Divisor Latch LSB }
- DLM = $3F9; { 8250 Divisor Latch MSB }
- DLAB = $80; { 8250 Divisor Latch Access Bit }
-
-
- BAUD300 = 384; { Value for 300 baud operation }
- BAUD1200 = 96; { Value for 1200 baud operation }
- NOPARITY = 0; { Comm format value for no parity }
- BITS8 = $03; { Comm format value for 8 bits }
- DTR = $01; { Value for Data Terminal Ready }
- RTS = $02; { value for Ready To Send }
- OUT2 = $08; { Bit that enables adapter interrupts }
-
- { 8259 control registers, masks, etc. }
- OCW1 = $21; { 8259 Operation Control Word 1 }
- OCW2 = $20; { 8259 Operation Control Word 2 }
- IRQ4 = $10; { Mask to turn IRQ4 interrupts on/off }
-
-
-
-
- TYPE
- CircularBuffer = ARRAY[0..1023] OF Char; { A 1K input buffer }
-
-
- VAR
- Quit : Boolean; { Flag for exiting the program }
- HiBaud : Boolean; { True if 1200 baud is being used }
- KeyChar : Char; { Character from keyboard }
- CommChar : Char; { Character from the comm port }
- Divisor : Word; { Divisor value for setting baud rate }
- Clearit : Byte; { Dummy variable }
- Buffer : CircularBuffer; { Our incoming character buffer }
- LastRead, { Index of the last character read }
- LastSaved : Integer; { Index of the last character stored }
- NoShow : SET OF Char; { Don't show characters set }
- OldVector : Pointer; { Global storage slot for the old }
- { interrupt vector }
-
-
- {$I SHOWHELP.SRC} { JTerm's minimal help system }
-
-
- PROCEDURE EnableInterrupts;
-
- INLINE($FB);
-
-
-
- {->>>>Incoming (Interrupt Service Routine)<<<<-----------------}
- { }
- { This is the ISR (interrupt Service Routine) for COM1. Note: }
- { DO NOT call this routine directly; you'll crash hard. The }
- { only way Incoming takes control is when a character coming }
- { in from the modem triggers a hardware interrupt from the }
- { serial port chip, the 8250 UART. Note that the register }
- { pseudo-parameters are not needed here, and you could omit }
- { them. However, omitting them doesn't really get you any }
- { more speed or reliability. }
- {--------------------------------------------------------------}
-
-
- PROCEDURE Incoming(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : Word);
- INTERRUPT;
-
- BEGIN
- { Our first job is to enable interrupts during the ISR: }
- EnableInterrupts;
- { The first "real work" we do is either wrap or increment the index }
- { of the last character saved. If the index is "topped out" at }
- { 1023, we force it to zero. This makes the 1024-byte buffer }
- { "circular," in that once the index hits the end, it rolls over to }
- { the beginning again. }
- IF LastSaved >= 1023 THEN LastSaved := 0 ELSE Inc(LastSaved);
-
- { Next, we read the actual incoming character from the serial port's}
- { one-byte holding buffer: }
- Buffer[LastSaved] := Char(Port[RBR]);
-
- { Finally, we must send a control byte to the 8259 interrupt }
- { controller, telling it that the interrupt is finished: }
- Port[OCW2] := $20; { Send EOI byte to 8259 }
- END;
-
-
-
- {$F+}
- PROCEDURE JTermExitProc;
-
- BEGIN
- Port[IER] := 0; { Disable interrupts at 8250 }
- Port[OCW1] := Port[OCW1] OR IRQ4; { Disable IRQ4 at 8259 }
- Port[MCR] := 0; { Bring the comm line down }
- SetIntVec(Com1Int,OldVector); { Restore previously saved vector }
- END;
- {$F-}
-
-
-
- PROCEDURE SetupSerialPort;
-
- BEGIN
- LastRead := 0; { Initialize the circular buffer pointers }
- LastSaved := 0;
-
- Port[IER] := 0; { Disable interrupts while we're setting them up }
-
- GetIntVec(Com1Int,OldVector); { Save old IRQ4 vector }
- ExitProc := @JTermExitProc; { Hook exit proc into chain }
- SetIntVec(Com1Int,@Incoming); { Put ISR address into vector table }
-
- Port[LCR] := Port[LCR] OR DLAB; { Set up 8250 to set baud rate }
- Port[DLL] := Lo(Divisor); { Set baud rate divisor }
- Port[DLM] := Hi(Divisor);
- Port[LCR] := BITS8 OR NOPARITY; { Set word length and parity }
- Port[MCR] := DTR OR RTS OR OUT2; { Enable adapter, DTR, & RTS }
- Port[OCW1] := Port[OCW1] AND (NOT IRQ4); { Turn on 8259 IRQ4 ints }
- Clearit := Port[RBR]; { Clear any garbage from RBR }
- Clearit := Port[LSR]; { Clear any garbage from LSR }
-
- Port[IER] := $01; { Enable interrupt on received character }
- END;
-
-
- FUNCTION InStat : Boolean;
-
- BEGIN
- IF LastSaved <> LastRead THEN InStat := True
- ELSE InStat := False;
- END;
-
-
- FUNCTION InChar : Char; { Bring in the next character }
- { from the ring buffer }
- BEGIN
- IF LastRead >= 1023 THEN LastRead := 0
- ELSE LastRead := Succ(LastRead);
- InChar := Buffer[LastRead];
- END;
-
-
- PROCEDURE OutChar(Ch : Char); { Send a character to the comm port }
-
- BEGIN
- Port[THR] := Byte(Ch) { Put character ito Transmit Holding Register }
- END;
-
-
- {>>>>>JTERM MAIN PROGRAM<<<<<}
-
- BEGIN
- HiBaud := True; { JTerm defaults to 1200 baud; if "300" }
- Divisor := BAUD1200; { is entered after "JTERM" on the command }
- IF ParamCount > 0 THEN { line, then 300 baud is used instead. }
- IF ParamStr(1) = '300' THEN
- BEGIN
- HiBaud := False;
- Divisor := BAUD300
- END;
-
- DirectVideo := True;
- NoShow := [#0,#127]; { Don't display NUL or RUBOUT }
- SetupSerialPort; { Set up serial port & turn on interrupts }
-
-
- ClrScr;
- Writeln('>>>JTERM by Jeff Duntemann');
-
- Quit := False; { Exit JTERM when Quit goes to True }
- REPEAT
-
- IF InStat THEN { If a character comes in from the modem }
- BEGIN
- CommChar := InChar; { Go get character }
- CommChar := Char(Byte(CommChar) AND $7F); { Mask off high bit }
- IF NOT (CommChar IN NoShow) THEN { If we can show it,}
- Write(CommChar) { then show it! }
- END;
-
- IF KeyPressed THEN { If a character is typed at the keyboard }
- BEGIN
- KeyChar := ReadKey; { First, read the keystroke }
- IF KeyChar = Chr(0) THEN { We have an extended scan code here }
- BEGIN
- KeyChar := ReadKey; { Read second half of extended code }
- CASE Ord(KeyChar) OF
- 59 : ShowHelp; { F1 : Display help screen }
- END { CASE }
- END
- ELSE
- CASE Ord(KeyChar) OF
- 24 : Quit := True; { Ctrl-X: Exit JTerm }
- 26 : ClrScr; { Ctrl-Z: Clear the screen }
- ELSE OutChar(KeyChar)
- END; { CASE }
- END
-
- UNTIL Quit
- END.