home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Between Heaven & Hell 2
/
BetweenHeavenHell.cdr
/
500
/
433
/
pyserial.inc
< prev
next >
Wrap
Text File
|
1986-12-23
|
20KB
|
808 lines
FUNCTION GotCarrier : BOOLEAN;
BEGIN
IF NOT Comm
THEN GotCarrier := FALSE
ELSE
BEGIN
IF (PORT[ModemStatus] AND $80) > 0
THEN GotCarrier := TRUE
ELSE GotCarrier := FALSE;
END;
END;
PROCEDURE SetBaud(BaudRate : INTEGER);
BEGIN
IF Comm THEN
BEGIN
PORT[IntReg] := 0;
PORT[LineContrl] := $80;
PORT[LowBaud] := LO(TRUNC(BaudConst / BaudRate));
PORT[HighBaud] := HI(TRUNC(BaudConst / BaudRate));
PORT[LineContrl] := 3;
PORT[ModemContrl] := 3;
END;
END;
FUNCTION GotComChar : BOOLEAN;
BEGIN
GotComChar := FALSE;
IF Comm THEN IF ((PORT[StatusPort] AND RReady) > 0)
THEN GotComChar := TRUE;
END;
FUNCTION TransmitReady : BOOLEAN;
BEGIN
TransmitReady := FALSE;
IF Comm THEN IF ((PORT[StatusPort] AND TReady) <> 0)
THEN TransmitReady := TRUE;
END;
FUNCTION AnyKeyPressed : BOOLEAN;
BEGIN
AnyKeyPressed := FALSE;
IF GotComChar THEN AnyKeyPressed := TRUE;
IF KEYPRESSED THEN AnyKeyPressed := TRUE;
END;
FUNCTION LostCarrier : BOOLEAN;
BEGIN
LostCarrier := FALSE;
IF Comm THEN IF HadCarrier <> GotCarrier THEN LostCarrier := TRUE;
END;
FUNCTION SerialIn : CHAR;
VAR
CHARIn : CHAR;
CmdChar : CHAR;
GotEvent : BOOLEAN;
TimeInner : INTEGER;
TimeOut : BOOLEAN;
TimeOuter : INTEGER;
BEGIN
{----- Loop until something other than a FnKey request -----}
REPEAT
TimeInner := 0;
TimeOut := FALSE;
TimeOuter := 0;
GotEvent := FALSE;
{--- Wait for a char or event from somewhere ---}
REPEAT
TimeInner := TimeInner + 1;
IF TimeInner = 3000 THEN
BEGIN
TimeInner := 0;
TimeOuter := TimeOuter + 1;
IF TimeOuter = TimeOutSecs THEN TimeOut := TRUE;
END;
IF AnyKeyPressed OR LostCarrier OR TimeOut OR SysFail THEN GotEvent := TRUE;
UNTIL GotEvent;
{--- Process the event ---}
IF LostCarrier OR TimeOut OR SysFail THEN
BEGIN
IF LostCarrier OR (TimeOutCntr > 3) THEN Logoff := TRUE;
IF TimeOut THEN TimeOutCntr := TimeOutCntr + 1;
CHARIn := ^M;
END
ELSE
BEGIN
TimeOutCntr := 0;
IF KEYPRESSED
THEN
BEGIN
READ(KBD,CHARIn);
IF CHARIn = #27 THEN DoFnKeys;
END
ELSE CHARIn := CHR(PORT[DataPort]);
CHARIn := CHR(BYTE(CHARIn) AND $7F);
END;
IF ((CHARIn < #27) AND (NOT (CHARIn IN [^B,^H,^M,^S,^X])))
OR (CHarin > #126) THEN CHARIn := '.';
UNTIL (CHARIn <> #27) OR ExFnKey;
Last2Char := LastChar;
LastChar := CHARIn;
SerialIn := CHARIn;
END;
PROCEDURE AwaitSend;
BEGIN
REPEAT UNTIL TransmitReady OR LostCarrier;
END;
PROCEDURE SerialOut(OutChar : CHAR);
VAR
SLCntr : INTEGER;
BEGIN
{----- Send char to modem when ready -----}
IF GotCarrier THEN
BEGIN
AwaitSend;
{--- Defuse attempt to send ATTN code to modem from remote ---}
IF (LastChar = Attn[2]) THEN
BEGIN
IF (Last2Char = Attn[1]) THEN
BEGIN
PORT[DataPort] := 20;
AwaitSend;
PORT[DataPort] := 08;
AwaitSend;
END;
END;
PORT[DataPort] := ORD(OutChar);
END;
{----- Check for character during output -----}
IF AnyKeyPressed AND (NOT Inputting) THEN
BEGIN
CharDuringO := TRUE;
DuringOChar := SerialIn;
IF ExFnKey
THEN
BEGIN
ExFnKey := FALSE;
CharDuringO := FALSE;
END
ELSE
BEGIN
IF (DuringOChar IN [^S, 'P', 'p']) THEN
BEGIN
CharDuringO := FALSE;
REPEAT UNTIL AnyKeyPressed OR LostCarrier;
DuringOChar := SerialIn;
END; { Pausing }
END; { Not after FnKey }
END; { Char during output }
{----- Update the console -----}
IF (OutChar <> ^Q) AND (OutChar <> ^G) THEN WRITE(OutChar);
IF OutChar = ^J THEN
BEGIN
GetDate;
IF SaveTime <> Mint THEN StatusLine;
END;
END;
PROCEDURE XLF;
BEGIN
IF NOT SuppressOut THEN
BEGIN
SerialOut(^M);
SerialOut(^J);
END
END;
PROCEDURE SendLine(OutLine : Line);
VAR
CHARPosn : BYTE;
XInChar : CHAR;
XLen : INTEGER;
BEGIN
IF NOT SuppressOut THEN
BEGIN
XLen := LENGTH(OutLine);
IF XLen <> 0 THEN
BEGIN
CHARPosn := 0;
REPEAT
IF AnyKeyPressed AND (Adding OR Contacting) AND Wrapping
THEN
BEGIN
XInChar := SerialIn;
IF XInChar > #27 THEN
BEGIN
InputLen := InputLen + 1;
IF InputLen > 100 THEN InputLen := 100;
InputLine[InputLen] := XInChar;
END;
END
ELSE
BEGIN
{----- Spaced out a file transmit? -----}
IF OutFiling AND CharDuringO AND (DuringOChar = ' ')
THEN
BEGIN
XLen := CHARPosn;
XLF;
END
ELSE
BEGIN
CHARPosn := CHARPosn + 1;
SerialOut(OutLine[CHARPosn]);
IF CHARPosn > 1 THEN
BEGIN
IF (OutLine[CHARPosn-1] = ^H) THEN
BEGIN
IF OutLine[CHARPosn] <> ^H
THEN
IF ((BaudRate > 500) OR LocalUser)
THEN DELAY(75)
ELSE DELAY(15);
END; { Imbedded backspace }
END; { Worth checking for backspace }
END; { Output of file not interrupted }
END; { Not taking another character during wrap }
UNTIL (CHARPosn = XLen);
END; { Output longer than 0 }
END; { Output not suppressed }
END; { X }
PROCEDURE X(WorkLine : Line);
VAR
BSCntr : INTEGER;
FoundWrap : BOOLEAN;
WorkLen : INTEGER;
WorkPtr : INTEGER;
WorkWidth : INTEGER;
XLen : INTEGER;
BEGIN
WorkWidth := Width - 1;
{----- Step through the fragments -----}
REPEAT
WorkPtr := 999;
XLen := LENGTH(WorkLine);
IF XLen > WorkWidth THEN
BEGIN
{--- Find the maximum allowable ---}
FoundWrap := FALSE;
WorkPtr := 0;
BSCntr := 0;
REPEAT
WorkPtr := WorkPtr + 1;
IF WorkLine[WorkPtr] = ^H THEN BSCntr := BSCntr + 2;
IF WorkPtr - BSCntr = WorkWidth THEN FoundWrap := TRUE;
UNTIL FoundWrap;
{--- Step backwards to a wrap point ---}
FoundWrap := FALSE;
WorkPtr := WorkPtr + 1;
REPEAT
WorkPtr := WorkPtr - 1;
IF POS(WorkLine[WorkPtr],' .,?!:;)]%-+') > 0
THEN FoundWrap := TRUE;
{--- Is it a hopeless case? ---}
IF WorkPtr + BSCntr < BreakPoint THEN
BEGIN
WorkPtr := WorkWidth;
FoundWrap := TRUE;
END;
UNTIL FoundWrap;
END; { Needs wrapping }
{--- Send line, remove sent text, do linefeed if wrapping ---}
IF WorkPtr > XLen THEN WorkPtr := XLen;
SendLine(COPY(WorkLine,1,WorkPtr));
DELETE(WorkLine,1,WorkPtr);
IF LENGTH(WorkLine) > 0 THEN XLF; { Get ready for another piece }
UNTIL (LENGTH(WorkLine) = 0) OR (CharDuringO AND (DuringOChar = ' '));
END;
PROCEDURE XLn(OutLine : Line);
VAR CHARPosn : BYTE; BEGIN X(OutLine); XLF; END;
PROCEDURE XLnI(OutLine : Line); { Skippable Informatory Messages }
BEGIN { It's up to you to reset CharDuringO }
IF NOT (CharDuringO AND (DuringOChar = ' ')) THEN XLn(OutLine);
END; { XLnI }
PROCEDURE SlowX(SXLine : Line);
VAR
SXCntr : INTEGER;
BEGIN
FOR SXCntr := 1 TO LENGTH(SXLine) DO
BEGIN
SerialOut(SXLine[SXCntr]);
IF GotCarrier THEN DELAY(80);
END;
END;
PROCEDURE PySerialInit;
BEGIN
CharDuringO := FALSE;
Inputting := FALSE;
TimeOutCntr := 0;
TimeOutSecs := 10;
END;
PROCEDURE BackSpace;
BEGIN
IF InputLen > 0 THEN
BEGIN
BSCntr := BSCntr + 1;
InputLen := InputLen - 1;
SerialOut(^H); SerialOut(' '); SerialOut(^H);
END;
END;
PROCEDURE WrapWith(WWChar : CHAR); { New for Version 3.01 }
VAR
IWCChar : CHAR;
BEGIN
X(WWChar);
IF AnyKeyPressed AND (CmdLen < 100) THEN
BEGIN
IF KEYPRESSED
THEN READ(KBD,IWCChar)
ELSE IWCChar := CHR(PORT[DataPort]);
IF IWCChar < #27 THEN
BEGIN
CmdLen := CmdLen + 1;
CmdParm[CmdLen] := IWCChar;
END;
END;
END;
FUNCTION GetInput : Line;
VAR
BackCntr : INTEGER; { Renamed for Version 3.01 -- use FIND for others }
EndTime : REAL;
GIChar : CHAR;
GotInput : BOOLEAN;
StartTime : REAL;
WrapCntr : INTEGER;
WrapPtr : INTEGER;
BEGIN
GotInput := FALSE;
Inputting := TRUE;
InputLen := 0;
BSCntr := 0;
IF LENGTH(CmdParm) > 0 THEN
BEGIN
InputLine := CmdParm;
CmdParm := '';
IF NOT ((Adding OR Contacting) AND Wrapping) THEN GotInput:= TRUE;
WrapCntr := 0;
REPEAT
WrapCntr := WrapCntr + 1;
X(InputLine[WrapCntr]);
UNTIL (WrapCntr = InputLen); { Can be extended by X function }
END;
IF NOT GotInput THEN
BEGIN
SerialOut(^Q);
BackCntr := 0;
GetDate;
StartTime := Mint * 60 + Secs;
REPEAT
GIChar := SerialIn;
IF Contacting THEN
BEGIN
IF GIChar = ^M
THEN
BEGIN
SOUND(700);
DELAY(5);
END
ELSE
BEGIN
SOUND(1000+ORD(GIChar));
DELAY(1);
END;
NOSOUND;
END;
CASE GIChar OF
#27 : BEGIN END;
^M : GotInput := TRUE;
^X : WHILE InputLen > 0 DO BackSpace;
^H : BackSpace;
ELSE
IF GIChar = ^B THEN
BEGIN
GIChar := ^H; { Allow imbedded backspaces }
BackCntr := BackCntr + 2; { Removes two from screen }
END;
IF (InputLen - BackCntr < 76) AND (InputLen < 100) THEN
BEGIN
InputLen := InputLen + 1;
IF UpCaseInput THEN GIChar := UPCASE(GIChar);
InputLine[InputLen] := GIChar;
SerialOut(GIChar);
END;
IF (InputLen - BackCntr >= 76) AND Wrapping THEN
BEGIN
WrapPtr := InputLen + 1;
REPEAT
WrapPtr := WrapPtr - 1
UNTIL (InputLine[WrapPtr] = ' ') OR (WrapPtr < 55);
IF WrapPtr >= 55
THEN
BEGIN
IF WrapPtr <> InputLen
THEN
BEGIN
{ Next few lines changed for Version 3.01 to fix word-wrap }
CmdParm := COPY(InputLine, WrapPtr + 1, InputLen - WrapPtr);
FOR WrapCntr := (WrapPtr + 1) TO InputLen DO WrapWith(^H);
FOR WrapCntr := (WrapPtr + 1) TO InputLen DO WrapWith(' ');
END;
InputLen := WrapPtr - 1;
GotInput := TRUE;
END;
END;
END; { Not BS, CR, ESC or CTL-X }
UNTIL GotInput;
GetDate;
EndTime := Mint * 60 + Secs;
IF StartTime > EndTime { i.e. midnight-wrap } THEN
EndTime := EndTime + 86400.0;
InputTime := EndTime - StartTime;
END; { No CmdParm }
Inputting := FALSE;
GetInput := InputLine;
END;
FUNCTION GetInputLn : Line;
BEGIN
GetInputLn := GetInput;
X(^M+^J);
END;
FUNCTION GetInt(GIPrompt : Line) : INTEGER;
VAR
GotInt : BOOLEAN;
IntChar : CHAR;
TestNum : INTEGER;
VALxxx : INTEGER;
BEGIN
GotInt := FALSE;
IF (LENGTH(CmdParm) > 0)
THEN
BEGIN
VAL(CmdParm,TestNum,VALRetCode);
IF VALRetCode = 0 THEN
BEGIN
CmdParm := '';
GotInt := TRUE;
END
ELSE
BEGIN
IF VALRetCode = 1
THEN GotInt := FALSE
ELSE
BEGIN
VAL(COPY(CmdParm,1,VALRetCode - 1),TestNum,VALxxx);
GotInt := TRUE;
DELETE(CmdParm,1,VALRetCode);
END;
END;
IF GotInt THEN XLn(GIPrompt+IntToStr(TestNum));
END; { Had a stacked value }
IF NOT GotInt THEN
BEGIN
InputLine := '';
X(GIPrompt+^Q);
Inputting := TRUE;
REPEAT
IntChar := SerialIn;
IF IntChar IN ['0'..'9',^H,^M,^X]
THEN
BEGIN
CASE IntChar OF
#27 : BEGIN END;
^H : BackSpace;
^M : GotInt := TRUE;
^X : While InputLen > 0 DO BackSpace;
ELSE
InputLen := InputLen + 1;
IF InputLen > 5 THEN
BEGIN
InputLine := '32767';
GotInt := TRUE;
END
ELSE InputLine[InputLen] := IntChar;
SerialOut(IntChar);
END;
END;
IF Logoff THEN
BEGIN
GotInt := TRUE;
InputLine := '';
END;
UNTIL GotInt;
IF LENGTH(InputLine) = 0 THEN
BEGIN
InputLine := '0';
SerialOut('0');
END;
XLF;
Inputting := FALSE;
VAL(InputLine,TestNum,VALRetCode);
END; { No valid cmdparm }
IF TestNum < 0 THEN TestNum := 0;
GetInt := TestNum;
END;
PROCEDURE GetTestPass;
VAR
GTPChar : CHAR;
BEGIN
XLF;
X('<(*)> '+^Q);
TestPass := '';
Inputting := TRUE;
REPEAT
GTPChar := SerialIn;
IF GTPChar <> ^M THEN
BEGIN
IF GTPChar = ^H
THEN
BEGIN
IF LENGTH(TestPass) > 0 THEN
BEGIN
X(^H+' '+^H);
TestPass := COPY(TestPass,1,LENGTH(TestPass)-1);
END;
END
ELSE
BEGIN
TestPass := TestPass + UPCASE(GTPChar);
X('*');
END;
END;
UNTIL (GTPChar = ^M) OR (LENGTH(TestPass) = 10);
Inputting := FALSE;
END;
{======= Modem-Control Routines =======}
FUNCTION LocalSerialIn : CHAR;
VAR
LSChar : CHAR;
LSTimeOut : INTEGER;
BEGIN
LSTimeOut := 0;
REPEAT
LSTimeOut := LSTimeOut + 1;
UNTIL GotComChar OR (LSTimeOut = 5000);
IF LSTimeOut = 5000
THEN LSChar := '/'
ELSE LSChar := CHR(PORT[DataPort]);
LocalSerialIn := LSChar;
END;
PROCEDURE LocalSerialOut(LSOChar : CHAR);
BEGIN
REPEAT UNTIL ((PORT[StatusPort] AND TReady) > 0) OR KEYPRESSED;
PORT[DataPort] := ORD(LSOChar);
END;
PROCEDURE ModemShow(MSChar : TenType);
BEGIN
CASE MSChar OF
^J : BEGIN END;
^M : BEGIN END;
ELSE IF NOT SuppressOut THEN WRITE(MSChar);
END;
END;
FUNCTION ModemResponse : ComLine;
VAR
MRChar : CHAR;
MRLine : ComLine;
MRLen : BYTE ABSOLUTE MRLine;
TimeNow : INTEGER;
TimeStart : INTEGER;
BEGIN
{----- Give the modem some time to wake up -----}
GetDate;
TimeStart := Secs;
REPEAT
GetDate;
TimeNow := Secs;
IF TimeNow < TimeStart THEN TimeNow := TimeNow + 60; { Min. wrap }
UNTIL GotComChar OR (TimeNow - TimeStart > 3);
{----- Get the response, if any -----}
IF NOT GotComChar
THEN MRLine := '<TIME-OUT>'
ELSE
BEGIN
{----- Get the response -----}
MRLine := '';
MRLen := 0;
TimeStart := GetHSecs;
REPEAT
IF GotComChar THEN
BEGIN
TimeStart := GetHSecs;
MRChar := UPCASE(CHR(PORT[DataPort]));
ModemShow(MRChar);
IF MRLen = 40 THEN MRLen := 0;
MRLen := MRLen + 1;
MRLine[MRLen] := MRChar;
END;
TimeNow := GetHSecs;
IF TimeNow < TimeStart THEN TimeNow := TimeNow + 100; { Sec. wrap }
UNTIL TimeNow - TimeStart > 50;
END;
{----- Forward the response -----}
ModemResponse := MRLine;
IF NOT SuppressOut THEN WRITELN;
END;
FUNCTION WaitForOkay : ComLine;
VAR
FromModem : ComLine;
Response : ComLine;
BEGIN
GOTOXY(45,WHEREY);
WRITE('Response: ');
FromModem := ModemResponse;
IF POS(ModemOkay,FromModem) > 0
THEN WaitForOkay := ModemOkay
ELSE WaitForOkay := '<TIME-OUT>';
END;
PROCEDURE ModemCtrl(MCLine : ComLine);
VAR
MCCntr : INTEGER;
MCToss : CHAR;
MCTry : INTEGER;
BEGIN
IF
(
(NOT GotCarrier) OR ((MCLine = ModemHangUp) AND (DisconMethod = 'ATTN'))
)
AND Comm
THEN
BEGIN
MCTry := 0;
REPEAT
MCTry := MCTry + 1;
{=== Send the command ===}
WRITE(#17#16,' Modem: ');
FOR MCCntr := 1 TO LENGTH(MCLine) DO
BEGIN
IF MCLine[MCCntr] = '^'
THEN DELAY(100)
ELSE
BEGIN
LocalSerialOut(MCLine[MCCntr]);
ModemShow(LocalSerialIn);
END;
END;
{=== Catch up ===}
DELAY(100);
IF GotComChar THEN
BEGIN
ModemShow(LocalSerialIn);
DELAY(100);
END;
{=== Execute the command ===}
LocalSerialOut(^M);
UNTIL (WaitForOkay <> '<TIME-OUT>') OR (MCTry = 3);
END;
END;
PROCEDURE DropReady;
VAR
DREat : ComLine;
DRLoop : INTEGER;
BEGIN
IF HadCarrier THEN { Changed for 3.01 }
BEGIN
SetBaud(BaudRate); { New line for 3.01 }
SerialOut(^M); { New line for 3.01 }
SerialOut(^M); { New line for 3.01 }
IF DisconMethod = 'DTR'
THEN
BEGIN
PORT[ModemContrl] := 0;
DELAY(DisconDelay);
SetBaud(300);
WRITELN;
END
ELSE
BEGIN
WRITELN;
WRITE(#17#16+' Modem: ');
DELAY(DisconDelay);
FOR DRLoop := 1 TO LENGTH(Attn) DO
BEGIN
IF Attn[DRLoop] = '^'
THEN DELAY(10)
ELSE
BEGIN
DELAY(150);
LocalSerialOut(Attn[DRLoop]);
WRITE(Attn[DRLoop]);
END;
END;
DELAY(DisconDelay DIV 3);
DREat := WaitForOkay;
ModemCtrl(ModemHangUp);
END;
END;
END;
PROCEDURE DropCarrier;
VAR
DCNoise : ComLine;
DCCnt : INTEGER;
BEGIN
XLF; XLF;
FOR DCCnt := 1 TO 7 DO
BEGIN
SOUND(1000 - DCCnt * 25); DELAY(4); NOSOUND; DELAY(9);
END;
IF GotCarrier THEN
BEGIN
WRITE(#17#16+' Disconnecting...');
DropReady;
SuppressOut := TRUE;
DCNoise := ModemResponse; { NO CARRIER message or noise, etc. }
SuppressOut := FALSE;
END;
END;
PROCEDURE ResetAnswer;
BEGIN
IF LocalUser THEN ModemCtrl(ModemHangUp);
IF SysFail OR ShutDown
THEN
BEGIN
ModemCtrl(ModemNoAnswer);
ModemCtrl(ModemReset);
END
ELSE ModemCtrl(ModemDoAnswer);
END;
PROCEDURE ModemInit;
BEGIN
IF Comm THEN
BEGIN
SetBaud(300);
ModemCtrl(ModemAttn);
ModemCtrl(ModemConfig);
ModemCtrl(ModemHangUp);
ModemCtrl(ModemDoAnswer);
END;
END;
PROCEDURE AwaitUser;
VAR
AUChar : CHAR;
AULine : Line;
GotUser : BOOLEAN;
Response : ComLine;
BEGIN
WRITELN;
WRITELN(#17#16+' Awaiting visitor...');
WRITELN;
GotUser := FALSE;
LastChar := ' ';
Last2Char := ' ';
LocalUser := FALSE;
Response := '';
REPEAT
{--- Detect console user ---}
IF KEYPRESSED THEN
BEGIN
READ(KBD,AUChar);
IF AUChar = #27
THEN DoFnKeys
ELSE
BEGIN
ModemCtrl(ModemPickUp);
GotUser := TRUE;
HadCarrier := FALSE;
LocalUser := TRUE;
END;
END;
IF GotComChar THEN
BEGIN
AULine := ModemResponse;
{--- See if it's a valid response ---}
IF POS(Modem300 ,AULine) > 0 THEN Response := Modem300;
IF POS(Modem1200,AULine) > 0 THEN Response := Modem1200;
IF POS(Modem2400,AULine) > 0 THEN Response := Modem2400;
IF LENGTH(Response) > 0 THEN
BEGIN
WRITELN;
GotUser := TRUE;
HadCarrier := TRUE;
IF Response = Modem300 THEN
BEGIN BaudRate := 300; SetBaud(BaudRate); END;
IF Response = Modem1200 THEN
BEGIN BaudRate := 1200; SetBaud(BaudRate); END;
IF Response = Modem2400 THEN
BEGIN BaudRate := 2400; SetBaud(BaudRate); END;
END; { Got a recognizable modem response }
END; { Got a char at the modem }
UNTIL GotUser;
WRITELN; WRITELN(#17#16+' Connected.');
END;