(* °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° *) (* °°ÛÛÛÛÛÛ°°°°°°°°°°°°°°°°°°°°°ÛÛÛÛÛÛ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° *) (* °°Û °°°°°°°°°°°°°°°°°°°°Û °°°°°°°°°°ú ú°°°°° *) (* °°ÛÛÛÛÛÛ Û°°Û°ÛÛÛÛ°ÛßßÛ°ÛÜÛÛ°ÛÛÛ°°ÛÛÛÛ°Ûßßß°°° By Wayne Boyd ±°°°° *) (* °°° Û Û °Û Û Û Ûßßß Û Û °Û Û ßßßÛ°°° Fido 1:153/763 ±°°°° *) (* °°ÛÛÛÛÛÛ ÛÛÛÛ ÛÛÛÛ ÛÛÛÛ Û °°°Û °°°ÛÛÛÛ ÛÛÛÛ °°ú ú±°°°° *) (* °°° ° Û ° ° °°°° °°°° ° °°°±±±±±±±±±±±±±±±±°°°° *) (* °°°°°°°°°°°°°°Û °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° *) (* °°°°°°°°°°°°°°° °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° *) (* °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° *) (* °°°°°°°°°°°°°°°°°°°°°ú A Turbo Pascal Unit for ú°°°°°°°°°°°°°°°°° *) (* °°°°°°°°°°°°°°°°°°°°° modem communications using ±°°°°°°°°°°°°°°°° *) (* °°°°°°°°°°°°°°°°°°°°°ú a FOSSIL driver. ú±°°°°°°°°°°°°°°°° *) (* °°°°°°°°°°°°°°°°°°°°°°±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°°°°°°°°°°°°°° *) (* °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° *) (* Welcome to my fossil driver world. After struggling for a long *) (* time with various communications drivers I came to realize the *) (* easiest way to go about writing doors and even BBS programs was to *) (* use a FOSSIL driver. FOSSIL stands for Fido Opus Seadog Standard *) (* Interface Layer. It's a TSR program that remains in your computer *) (* memory and helps interface your software with the modem com port. *) (* There's many BBS programs, Fidonet mailer's and On-line BBS games *) (* that only operate with a FOSSIL driver loaded. The programs you *) (* write with this unit will also depend on a FOSSIL driver. *) (* Of course, there is no FOSSIL driver included with this package. *) (* You have to pick one of those up on your own at most major *) (* computer bulletin boards around country. I've tested this unit on *) (* X00, BNU and OPUSCOMM and they work fine. The unit that is *) (* included here is more a less a complete package. You could write a *) (* BBS or a door with it easily. I've written many doors now, and *) (* this is my standard unit. I don't want to claim credit for *) (* everything here. In fact, the function calls used are from the *) (* fossil revision 5 documentation and will work with any proper *) (* FOSSIL driver. *) (* *) (* = It is important to note that this unit was specifically written to *) (* = facilitate writing of BBS doors, but may be modified slightly to *) (* = facilitate the writing of a BBS program itself. The difference is *) (* = that generally when writing a door, if the caller drops carrier *) (* = you would simply want the program to terminate and return to the *) (* = BBS. In the case of a BBS, however, you want the BBS to recycle, *) (* = not to terminate. Also, with some doors, rather than terminate *) (* = immediately, you would want them to save information to file *) (* = first. In such cases you have to modify all of the HALT statements *) (* = that are found within this unit to reflect your actual needs. *) (* *) (* I have provided this unit as a public service for the BBS community, *) (* but I do request that if you would like further support for programs *) (* that you write with this unit, that you register this unit with me *) (* by sending me a modest donation of $25.00. *) (* *) (* I may be contacted by writing: *) (* ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ *) (* ³ Wayne Boyd ³ *) (* ³ c/o Vipramukhya Swami ³ *) (* ³ 5462 SE Marine Drive ³ *) (* ³ Burnaby, BC, V5J 3G8 ³ *) (* ³ Canada ³ *) (* ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ *) (* My BBS is called Sita and the Ring BBS, and it is Fidonet node *) (* 1:153/763, Transnet node 132:732/4 and ISKCONet 108:410/8. File *) (* requests and netmail is acceptable. You may also log on my board at *) (* 2400 baud or less, and the phone number is (604)431-6260. *) (* *) UNIT SuperFos; INTERFACE USES Dos,Crt,ansi; { this ANSI module is in ANSI.SWG. } CONST { These are defined global constants that can be passed to SetPort } Com0 = 0; { local only mode } Com1 = 1; { for COM1, etc. } Com2 = 2; Com3 = 3; Com4 = 4; PROCEDURE SetPort(Port : Integer); (* Set's ComPortNum to correct value, used by all procedures. Must be *) (* called first. Use the defined constants to make it easy. For *) (* example: SetPort(Com1) will assign COM1 as the input/output port. *) (* In reality, the numeric value of ComPortNum is (Port - 1). *) (* Calling SetPort with a 0 will cause all functions and *) (* procedure to function in local mode. You must make one call to *) (* SetPort at the beginning of your program before using any of the *) (* procedures or functions in this unit. *) (* *) (* If you use *) (* SetPort(Com0), all functions and procedures will function in local *) (* mode, since Com0 = 0. This will cause the value of ComPortNum to *) (* equal -1. *) PROCEDURE SetBaudRate(A : LongInt); { Set baud rate, 300/600/1200/2400/4800/9600/19200/38400 supported} PROCEDURE TransmitChar(A : Char); { Character is queued for transmission} FUNCTION TxCharNoWait(A : Char) : BOOLEAN; { Try to send char. Returns true if sent, false if buffer full} FUNCTION ReceiveChar : Char; { Next char in input buffer returned, waits if none avail} FUNCTION SerialStatus : Word; { AH bit 6, 1=output buffer empty AH bit 5, 1=output buffer not full AH bit 1, 1=input buffer overrun AH bit 0, 1=characters in input buffer AL bit 7, 1=carrier detect AL bit 3, 1=always} FUNCTION KeyPressedPort : Boolean; { Similar to KEYPRESSED. Returns TRUE if there is a character waiting in the input port. Uses the SerialStatus function above. } FUNCTION OutBufferFull : Boolean; { Returns TRUE if the Output Buffer is full. } FUNCTION OutBufferEmpty : Boolean; { Returns TRUE if the Output Buffer is empty. } FUNCTION OpenFossil : Boolean; { Open & init fossil. Returns true if a fossil device is loaded } PROCEDURE CloseFossil; { Disengage fossil from com port. DTR not changed} PROCEDURE SetDTR(A : Boolean); { Raise or lower DTR} PROCEDURE FlushOutput; { Wait for all output to complete} PROCEDURE PurgeOutput; { Zero output buffer and return immediately. Chars in buffer lost} PROCEDURE PurgeInput; { Zero input buffer and return immediately. Chars in buffer lost} FUNCTION CarrierDetect : Boolean; { Returns true if there is carrier detect } FUNCTION SerialInput : Boolean; { Returns true if there is a character ready to be input } PROCEDURE WriteChar(c : Char); { Write char to screen only with ANSI support} PROCEDURE FlowControl(A : Byte); { Enable/Disable com port flow control} PROCEDURE WritePort(s : string); { Write string S to the comport and echo it to the screen. Checks if the buffer is full, and if it is, waits until it is available. If Carrier is dropped, this procedure will halt the program.} PROCEDURE WritelnPort(s : string); { Same as WritePort, but adds a linefeed + CarrierReturn to the end of S } FUNCTION ReadKeyPort : char; { Like pascal's Readkey. Example: var ch : char; begin repeat ch := upcase(readkeyport); until ch in ['Y','N']; end. } PROCEDURE ReadPort(var C : char); { Similar to Pascal's Read(ch : char); This procedure will read the comport until a character is received. If no carrier is received it will wait and eventually time out. If carrier is dropped it will halt the program. The character is echoed to the local screen with ansi support. EXAMPLE var ch : char; begin ReadPort(Ch); end. } PROCEDURE ReadlnPort(var S : string); { Similar to Pascal's Readln(s : string); This procedure will read the comport until a carriage return is received, and assign the value to S. Carrier detect monitoring is enabled, and if the carrier is dropped the program will halt. Also there is a time out function. The characters are echoed to the local screen with ansi support. Example: var Rspns : string; begin ReadlnPort(Rspns); (* read a string from comport and store in Rspns *) end. } PROCEDURE HangUp; { Hangs up on the caller by lowering DTR until carrier is dropped, and then raising DTR again. } VAR Reg : Registers; { Saves on stack usage later } {-------------------------------------------------------------------------} IMPLEMENTATION Const TimeOut = 20000; VAR Status : Word; bt : byte; ComPortNum : Integer; PROCEDURE SetPort(Port : Integer); BEGIN ComPortNum := Port - 1; END; FUNCTION BitOn(Position, TestByte : Byte) : Boolean; { This function tests to see if a bit in TestByte is turned on (equal to one). The bit to test is indicated by the parameter Position, which can range from 0 (right-most bit) to 7 (left-most bit). If the bit indicated by Position is turned on, the BitOn function returns TRUE. } BEGIN bt := $01; bt := bt SHL Position; BitOn := (bt AND TestByte) > 0; END; PROCEDURE SetBaudRate(A : LongInt); BEGIN IF ComPortNum < 0 then exit; WITH Reg DO BEGIN AH := 0; DX := ComPortNum; AL := $63; IF A=38400 THEN AL:=$23 ELSE CASE A OF 300 : AL := $43; 600 : AL := $63; 1200 : AL := $83; 2400 : AL := $A3; 4800 : AL := $C3; 9600 : AL := $E3; 19200 : AL := $03; END; Intr($14, Reg); END; END; PROCEDURE TransmitChar(A : Char); BEGIN IF ComPortNum < 0 then exit; Reg.AH := 1; Reg.DX := ComPortNum; Reg.AL := Ord(A); Intr($14, Reg); END; FUNCTION TxCharNoWait(A : Char) : BOOLEAN; BEGIN IF ComPortNum < 0 then exit; Reg.AH := $0B; Reg.DX := ComPortNum; Intr($14,Reg); TxCharNoWait := (Reg.AX = 1); END; FUNCTION ReceiveChar : Char; BEGIN IF ComPortNum < 0 then ReceiveChar := readkey else begin Reg.AH := 2; Reg.DX := ComPortNum; Intr($14,Reg); ReceiveChar := Chr(Reg.AL); end; END; FUNCTION SerialStatus : Word; BEGIN Reg.AH := 3; Reg.DX := ComPortNum; Intr($14,Reg); SerialStatus := Reg.AX; END; FUNCTION KeyPressedPort : Boolean; { Similar to KEYPRESSED. Returns TRUE if there is a character waiting in the input port. Uses the SerialStatus function above. } VAR Status : Word; NextByte : byte; begin IF ComPortNum < 0 then KeyPressedPort := Keypressed else begin Status := SerialStatus; NextByte := hi(Status); KeyPressedPort := BitOn(0,NextByte); end; end; FUNCTION OutBufferFull : Boolean; { Returns TRUE if the Output Buffer is full. } begin IF ComPortNum < 0 then OutBufferFull := false else begin Status := SerialStatus; bt := hi(Status); OutBufferFull := (BitOn(5,bt) = FALSE); end; end; FUNCTION OutBufferEmpty : Boolean; { Returns TRUE if the Output Buffer is empty. } begin IF ComPortNum < 0 then OutBufferEmpty := true else begin Status := SerialStatus; bt := hi(Status); OutBufferEmpty := BitOn(6,bt); end; end; FUNCTION OpenFossil : boolean; BEGIN if ComPortNum < 0 then OpenFossil := true else begin Reg.AH := 4; Reg.DX := ComPortNum; Intr($14,Reg); OpenFossil := Reg.AX = $1954; end; END; PROCEDURE CloseFossil; BEGIN IF ComPortNum < 0 then exit; Reg.AH := 5; Reg.DX := ComPortNum; Intr($14,Reg); END; PROCEDURE SetDTR; BEGIN IF ComPortNum < 0 then exit; Reg.AH := 6; Reg.DX := ComPortNum; Reg.AL := Byte(A); Intr($14,Reg); END; PROCEDURE FlushOutput; BEGIN IF ComPortNum < 0 then exit; Reg.AH := 8; Reg.DX := ComPortNum; Intr($14,Reg); END; PROCEDURE PurgeOutput; BEGIN IF ComPortNum < 0 then exit; Reg.AH := 9; Reg.DX := ComPortNum; Intr($14,Reg); END; PROCEDURE PurgeInput; BEGIN IF ComPortNum < 0 then exit; Reg.AH := $0A; Reg.DX := ComPortNum; Intr($14,Reg); END; FUNCTION CarrierDetect; BEGIN IF ComPortNum < 0 then CarrierDetect := true else begin Reg.AH := 3; Reg.DX := ComPortNum; Intr($14,Reg); CarrierDetect := (Reg.AL AND $80) > 0; end; END; FUNCTION SerialInput; BEGIN IF ComPortNum < 0 then SerialInput := true else begin Reg.AH := 3; Reg.DX := ComPortNum; Intr($14,Reg); SerialInput := (Reg.AH And 1) > 0; end; END; PROCEDURE WriteChar(c : char); BEGIN if ComPortNum < 0 then Display_Ansi(c) else begin Reg.AH := $13; Reg.AL := ORD(c); Intr($14,Reg); end; END; PROCEDURE FlowControl; BEGIN IF ComPortNum < 0 then exit; Reg.AH := $0F; Reg.DX := ComPortNum; Reg.AL := A; Intr($14, Reg); END; PROCEDURE WritePort(s : string); VAR i : byte; begin for i := 1 to length(s) do begin if (ComPortNum >= 0) then TransmitChar(s[i]); DISPLAY_Ansi(s[i]); if not CarrierDetect then halt(1); end; end; PROCEDURE WritelnPort(s : string); BEGIN s := s + #10 + #13; WritePort(s); end; FUNCTION ReadKeyPort : char; var ch : char; count : longint; begin count := 0; repeat if not carrierdetect then exit; if ComPortNum < 0 then ch := readkey else if KeyPressedPort then ch := ReceiveChar else if keypressed then ch := readkey else ch := #0; if ch = #0 then inc(count); until (ch > #0) or (count > timeout); ReadKeyPort := ch; end; PROCEDURE ReadPort(var C : char); type C_Type = char; var CPtr : ^C_Type; ch : char; count : longint; begin CPtr := @C; count := 0; repeat if not carrierdetect then halt(1); if ComPortNum < 0 then ch := readkey else if KeyPressedPort then ch := ReceiveChar else if keypressed then ch := readkey else ch := #0; if ch = #0 then inc(count) else begin if (ComPortNum >= 0) then TransmitChar(ch); DISPLAY_Ansi(ch); end; until (ch > #0) or (count > timeout); CPtr^ := ch; end; PROCEDURE ReadlnPort(var S : string); type linestring = string; var SPtr : ^linestring; st : string; ch : char; begin SPtr := @S; st := ''; repeat Ch := readkeyport; if ch in [#32..#255] then begin st := st + ch; writeport(ch); end else if (ch = #8) and (st > '') then begin delete(st,length(st),1); writeport(#8+#32+#8); end; until ch in [#13,#0]; { will equal NULL if ReadPort timed out } WritelnPort(''); SPtr^ := st; end; PROCEDURE HangUp; BEGIN if ComPortNum < 0 then exit; repeat SetDtr(TRUE); { lower DTR to hangup } until Not CarrierDetect; SetDtr(FALSE); { raise DTR again } END; BEGIN Clrscr; Write('SuperFos - by Wayne Boyd 1:153/763'); delay(1000); END.