home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Computer Club Elmshorn Atari PD
/
CCE_PD.iso
/
pc
/
0500
/
CCE_0544.ZIP
/
CCE_0544
/
MX2
/
MX2SRC.ARC
/
NETWORK.MOD
< prev
next >
Wrap
Text File
|
1989-01-05
|
28KB
|
853 lines
(* Copyright 1987 fred brooks LogicTek *)
(* *)
(* *)
(* First Release 12/8/87-FGB *)
(* *)
IMPLEMENTATION MODULE NETWORK ;
(* --------------------------------------------------------------------------
NETWORK : MIDI PORT TWO CPU NETWORK FOR TDI Modula-2/ST
--------------------------------------------------------------------------*)
(*$T-,$S-,$A+ *)
FROM SYSTEM IMPORT ADDRESS, ADR, SETREG, CODE, REGISTER ,BYTE ,TSIZE;
FROM BIOS IMPORT BPB ,BConStat ,BConIn, BCosStat, BConOut, Device,
MediaChange,MCState,GetBPB,RWAbs,RW,DriveSet,DriveMap;
FROM XBIOS IMPORT SuperExec,IORec,IORECPTR,IOREC,SerialDevice;
FROM GEMDOS IMPORT TermRes,Open,Close ;
IMPORT GEMDOS;
FROM ASCII IMPORT SYN,STX,SOH,BEL;
CONST
MaxSeq = 1;
recsize = 511;
USER = 324159265;
retry = 10;
debug = FALSE;
trace = FALSE;
(* Because we dont know what registers the BIOS is using we must use
the following opcodes to save the registers *)
MOVEMDEC = 48E7H ; (* 68000 opcode for MOVEM <regs>,-(A7) *)
MOVEMINC = 4CDFH ; (* 68000 opcode for MOVEM (A7)+,<regs> *)
SAVEREGS = 07FFCH ; (* Registers D1..A5 for DEC *)
RESTREGS = 03FFEH ; (* Registers D1..A5 for INC *)
RTS = 04E75H ; (* 68000 return from subroutine opcode *)
TYPE
(* Procedure types to mimic correct sequence for "C" BIOS routines *)
CBPBProc = PROCEDURE ( CARDINAL ) ;
CMediaChProc = PROCEDURE ( CARDINAL ) ;
CRWAbsProc = PROCEDURE ( CARDINAL, CARDINAL, CARDINAL, ADDRESS, CARDINAL );
MIDIbuffer = ARRAY [0..512] OF CARDINAL;
SequenceNr = [0..MaxSeq];
message = ARRAY [0..recsize] OF BYTE;
message1 = ARRAY [0..17] OF BYTE;
FrameKind = (ack,data,callreq,callaccp,clearreq,clearconf,
resetreq,resetconf,diag);
DataKind = (rdmediareq,rdmediaconf,rdbpbreq,rdbpbconf,
rdrwabsreq,rdrwabsconf);
evtype = (framearrival,cksumerr,timeout,hostready,reset,nothing);
frame = RECORD
syn : CHAR; (* these are sync chars *)
stx : CHAR; (* for the frames *)
kind : FrameKind;
seq : SequenceNr;
ack : SequenceNr;
cmd : DataKind;
rw : CARDINAL; (* read or write data *)
recno : CARDINAL; (* sector for data*)
d0 : LONGCARD; (* data return variable *)
info : message;
user : LONGCARD;
cksum : CARDINAL;
END;
framecptr = POINTER TO framecmd;
framecmd = RECORD
syn : CHAR; (* these are sync chars *)
stx : CHAR; (* for the frames *)
kind : FrameKind;
seq : SequenceNr;
ack : SequenceNr;
cmd : DataKind;
rw : CARDINAL; (* read or write data *)
recno : CARDINAL; (* sector for data*)
d0 : LONGCARD; (* data return variable *)
info : message1;
user : LONGCARD;
cksum : CARDINAL;
END;
control = RECORD
magic : LONGCARD;
reset : BOOLEAN;
networkactive : BOOLEAN;
remotedrive : CARDINAL;
drivemap : DriveSet;
nextframetosend : SequenceNr;
frameexpected : SequenceNr;
sendreset : BOOLEAN;
END;
consave = RECORD
magic : LONGCARD;
reset : BOOLEAN;
networkactive : BOOLEAN;
END;
frameptr = POINTER TO ARRAY [0..1024] OF BYTE;
VAR
(* BIOS variables : These can only be accessed with the 68000 in supervisor
mode. The Modula-2 language allows you to fix the location of variables *)
HDBPB [0472H] : ADDRESS ; (* hard disk get Bios Parameter Block *)
HDRWAbs [0476H] : ADDRESS ; (* hard disk read/write abs *)
HDMediaCh [047EH] : ADDRESS ; (* hard disk media change *)
DriveBits [04C2H] : SET OF [0..31]; (* disk drives present map *)
flock [043EH] : LONGCARD; (* disk access in progress *)
hz200 [04baH] : LONGCARD; (* 200hz clock counter *)
clock : LONGCARD;
Dptr : DriveSet; (* save original drive map *)
Mptr : LONGCARD;
charcount,j,framesize,cksum,recframesize,sndframesize,
SIZEframe,SIZEframecmd : CARDINAL;
networkconnect : BOOLEAN; (* DCD = 1 TRUE *)
gotframe : BOOLEAN;
framebufferfull : BOOLEAN;
cleartosend : BOOLEAN;
readytosend : BOOLEAN;
requesttosend : BOOLEAN;
framewaiting : BOOLEAN;
timer,OK,installed : BOOLEAN;
gotmediach : ARRAY [0..5] OF BOOLEAN;
gotbpb : ARRAY [0..5] OF BOOLEAN;
networkerror : BOOLEAN;
shortframe : BOOLEAN;
sendlong : BOOLEAN;
sframe,rframe,SFRAME,RFRAME,
nframe1,nframe2 : frame;
rframeptr,sframeptr,
bpbptr,nbpbptr : frameptr;
framecmdptr,framecmdptr1 : framecptr;
event : evtype;
C : control;
recchar,timestart,timefortimeout,timeouttime : LONGCARD;
timestart1,timefortimeout1,timeouttime1 : LONGCARD;
result,r,i,i1,i2,i3,mediacount,handle : INTEGER;
D0ptr : POINTER TO LONGCARD;
wsector,drvnr,DriveA,DriveF,devicestart,d,R : CARDINAL;
rbuffer : MIDIbuffer;
rbptr : IORECPTR;
numBytes,sec,min,hour,time,count : LONGCARD ;
status : LONGINT ;
(* The following are saved copies of the BIOS variables so that the real
hard disk routines can be called if a hard disk access is requested. *)
SaveHDBPB : CBPBProc ; (* hard disk get Bios Parameter Block *)
SaveHDRWAbs : CRWAbsProc ; (* hard disk read/write abs *)
SaveHDMediaCh : CMediaChProc ; (* hard disk media change *)
(* NETWORK control *)
NetworkBPB : ARRAY [0..5] OF BPB ; (* BIOS Parameter block for NETWORK *)
PROCEDURE MoveMemory ( From, To : ADDRESS ; Bytes : LONGCARD ) ;
(* This routine shows how time critical portions of code can be optimised to
run faster. It relys on the code generation rules of the compiler which
can be checked by dis-assembling the link file with DecLnk.*)
CONST
MOVEB = 12D8H ; (* MOVE.B (A0)+,(A1)+ *)
MOVEL = 22D8H ; (* MOVE.L (A0)+,(A1)+ *)
A0 = 0+8 ; (* register A0 *)
A1 = 1+8 ; (* register A1 *)
BEGIN
SETREG(A0,From) ; (* load From pointer into A0 *)
SETREG(A1,To) ; (* load To pointer into A1 *)
IF ( ODD(From) OR ODD(To) ) THEN (* must do bytes *)
WHILE ( Bytes <> 0 ) DO
CODE(MOVEB) ;
DEC(Bytes) ;
END ;
ELSE (* even addresses so can do long moves *)
WHILE ( Bytes > 3 ) DO
CODE(MOVEL) ;
DEC(Bytes,4) ;
END ;
WHILE ( Bytes <> 0 ) DO
CODE(MOVEB) ; (* clean up remainder *)
DEC(Bytes) ;
END ;
END ;
END MoveMemory ;
PROCEDURE inc(VAR k: SequenceNr); (* increment k circulary *)
BEGIN
IF k<MaxSeq THEN k:=k+1 ELSE k:=0 END;
END inc;
(* The following procedures mimic the disk handling routines called by the
BIOS. Their procedure declarations have been written to mimic the "C"
calling sequence. *)
PROCEDURE RDRWAbs ( device, RecordNum, SectorCount : CARDINAL ;
Buffer : ADDRESS ; Flag : CARDINAL ) ;
(* NB. It is assumed that GEMDOS wont call this routine with out of range
parameters *)
CONST D0 = 0 ;
BEGIN
CODE(MOVEMDEC,SAVEREGS) ; (* save registers on stack *)
status := 0;
IF (device >= DriveA) AND (device <=DriveF) THEN (* is NETWORK channel *)
IF ( Flag = 0 ) OR ( Flag = 2 ) (* read *) THEN
FOR wsector:=0 TO (SectorCount-1) DO
C.remotedrive:=device-devicestart;
nframe1.d0:=LONGCARD(device-devicestart);
nframe1.recno:=RecordNum+wsector;
nframe1.rw:=Flag; (* read *)
resetnewdisk;
IF getfromremote(rdrwabsreq,rdrwabsconf,nframe1) THEN
MoveMemory(ADR(nframe1.info),Buffer+ADDRESS(wsector)*512,
512);
status:=0;
ELSE
status:=(-11);
END; (* if *)
END; (* for *)
IF networkerror THEN C.sendreset:=TRUE END; (* send network reset to remote cpu *)
SETREG(D0,status) ;
ELSIF ( Flag = 1 ) OR ( Flag = 3 ) THEN (* write *)
FOR wsector:=0 TO (SectorCount-1) DO
C.remotedrive:=device-devicestart;
nframe1.d0:=LONGCARD(device-devicestart);
nframe1.recno:=RecordNum+wsector;
nframe1.rw:=Flag; (* write *)
resetnewdisk;
MoveMemory(Buffer+ADDRESS(wsector)*512,ADR(nframe1.info),512);
IF getfromremote(rdrwabsreq,rdrwabsconf,nframe1) THEN
status:=0;
ELSE
status:=(-10);
END;
END; (* for *)
IF networkerror THEN C.sendreset:=TRUE END; (* send network reset to remote cpu *)
SETREG(D0,status) ;
ELSE
SETREG(D0,LONGINT(-3)) ;
END ;
ELSE (* not NETWORK *)
SaveHDRWAbs (device,RecordNum,SectorCount,Buffer,Flag) ;
END ;
CODE(MOVEMINC,RESTREGS) ; (* Restore registers from stack *)
END RDRWAbs ;
PROCEDURE RDMediaCh ( device : CARDINAL ) ;
CONST D0 = 0 ;
BEGIN
CODE(MOVEMDEC,SAVEREGS) ; (* save registers on stack *)
IF (device >= DriveA) AND (device <=DriveF) THEN (* is NETWORK channel *)
C.remotedrive:=device-devicestart;
nframe1.d0:=LONGCARD(device-devicestart);
IF newdisk() THEN
gotmediach[device-devicestart]:=FALSE;
gotbpb[device-devicestart]:=FALSE;
END;
IF (NOT gotmediach[device-devicestart]) THEN
IF getfromremote(rdmediareq,rdmediaconf,nframe1) THEN
gotmediach[device-devicestart]:=TRUE;
IF nframe1.d0=1 THEN nframe1.d0:=2 END;
SETREG(D0,nframe1.d0) ; (* "C" uses D0 as return location *)
ELSE
SETREG(D0,Changed);
END;
ELSE
SETREG(D0,NoChange) ; (* "C" uses D0 as return location *)
END;
ELSE (* not NETWORK *)
SaveHDMediaCh(device) ;
END;
CODE(MOVEMINC,RESTREGS) ; (* Restore registers from stack *)
END RDMediaCh ;
PROCEDURE RDBPB ( device : CARDINAL ) ;
CONST D0 = 0 ;
BEGIN
CODE(MOVEMDEC,SAVEREGS) ; (* save registers on stack *)
IF (device >= DriveA) AND (device <=DriveF) THEN (* is NETWORK channel *)
C.remotedrive:=device-devicestart;
nframe1.d0:=LONGCARD(device-devicestart);
IF newdisk() THEN gotbpb[device-devicestart]:=FALSE; gotmediach[device-devicestart]:=FALSE END;
(* gotbpb[device-devicestart]:=FALSE; (* test *) *)
IF (NOT gotbpb[device-devicestart]) THEN
IF getfromremote(rdbpbreq,rdbpbconf,nframe1) THEN
gotbpb[device-devicestart]:=TRUE;
bpbptr:=ADR(nframe1.info);
nbpbptr:=ADR(NetworkBPB[device-devicestart]);
FOR i3:=0 TO TSIZE(BPB)-1 DO
nbpbptr^[i3]:=bpbptr^[i3];
END;
resetnewdisk;
SETREG(D0,ADR(NetworkBPB[device-devicestart])); (* D0 returns address of the BPB *)
ELSE
SETREG(D0,0);
END;
ELSE
SETREG(D0,ADR(NetworkBPB[device-devicestart])); (* D0 returns address of the BPB *)
END;
IF networkerror THEN C.sendreset:=TRUE END; (* send network reset to remote cpu *)
ELSE (* not NETWORK *)
SaveHDBPB(device) ;
END ;
CODE(MOVEMINC,RESTREGS) ; (* Restore registers from stack *)
END RDBPB ;
PROCEDURE resetnewdisk;
BEGIN
SuperExec(gettime);
timestart1:=clock;
timefortimeout1:=timestart1;
IncTime(timefortimeout1,2);
END resetnewdisk;
PROCEDURE newdisk(): BOOLEAN;
BEGIN
SuperExec(gettime);
timeouttime1:=clock;
SETREG(0,timeouttime1);
CODE(0280H,0,0FFFFH);
timeouttime1:=LONGCARD(REGISTER(0));
IF timeouttime1>timefortimeout1 THEN
resetnewdisk;
RETURN TRUE;
END;
RETURN FALSE;
END newdisk;
(* ----------------------------------------------------------------------- *)
PROCEDURE Initialise (port: Device) : BOOLEAN ;
(* returns TRUE if NETWORK is to be installed *)
BEGIN
CODE(3f3cH,0017H,4e4eH,548fH); (* gettime *)
CODE(2f00H,3f3cH,0016H,4e4eH,5c8fH); (* settime *)
IF NOT installed THEN
SuperExec(PROC(setcontrol)); (* set address of global control record *)
END;
IF port=HSS THEN
rbptr:=IORec(MIDI);
ELSE
rbptr:=IORec(RS232);
END;
rbptr^.ibuf:=ADR(rbuffer);
rbptr^.ibufsize:=1024;
C.magic:=USER;
C.remotedrive:=0;
framesize:=TSIZE(frame);
recframesize:=framesize;
sndframesize:=framesize;
sframe.user:=USER;
R:=0;
RETURN TRUE;
END Initialise ;
(*$P- *) (* set vector to control record *)
PROCEDURE setcontrol;
BEGIN
IF Mptr#USER THEN
C.drivemap:=DriveMap();
Dptr:=C.drivemap;
END;
C.drivemap:=Dptr;
Mptr:=USER;
CODE(RTS);
END setcontrol;
PROCEDURE nrecframe;
BEGIN
IF C.networkactive THEN
WHILE (BConStat(netdevice)) AND (NOT framebufferfull) DO
recchar := BConIn(netdevice);
IF (CHAR(recchar)=SYN) AND (NOT gotframe) THEN
gotframe:=TRUE; (* got sync char from data *)
charcount:=0;
END;
IF (charcount=1) AND ((CHAR(recchar)#STX) AND (CHAR(recchar)#SOH)) THEN
gotframe:=FALSE; (* false start try again *)
charcount:=0;
END;
IF (charcount=1) AND (CHAR(recchar)=STX) THEN
recframesize:=SIZEframe;
END;
IF (charcount=1) AND (CHAR(recchar)=SOH) THEN
recframesize:=SIZEframecmd;
END;
IF gotframe THEN (* put data in buffer *)
rframeptr^[charcount]:=BYTE(recchar);
INC(charcount);
IF charcount=recframesize THEN (* got full frame *)
gotframe := FALSE;
IF trace THEN BConOut(CON,"^") END;
IF recframesize=SIZEframecmd THEN
rframe.user:=framecmdptr^.user;
rframe.cksum:=framecmdptr^.cksum;
END;
framebufferfull := TRUE;
END;
END;
END; (* WHILE *)
END;
END nrecframe;
(* The following compiler directive stops the compiler from generating the
normal Modula-2 entry/exit code for the next procedure. This is needed as
this routine is called in supervisor mode by the BIOS function to install
the BIOS vectors. *)
(*$P- Stop entry/exit code for next procedure *)
PROCEDURE InstallVectors ;
BEGIN
(* First save the current hard disk vectors *)
SaveHDBPB := CBPBProc(HDBPB) ;
SaveHDRWAbs := CRWAbsProc(HDRWAbs) ;
SaveHDMediaCh := CMediaChProc(HDMediaCh) ;
(* Now set the BIOS vectors to our routines *)
HDBPB := ADDRESS(RDBPB) ;
HDRWAbs := ADDRESS(RDRWAbs) ;
HDMediaCh := ADDRESS(RDMediaCh) ;
drvnr:=2;
WHILE drvnr IN DriveBits DO
INC(drvnr);
END; (* while *)
INC(drvnr);
devicestart:=drvnr;
DriveA:=drvnr;
DriveF:=drvnr+5;
INCL(DriveBits,drvnr) ; (* set new drive A *)
INCL(DriveBits,drvnr+1) ; (* set new drive B *)
INCL(DriveBits,drvnr+2) ; (* set new drive C *)
INCL(DriveBits,drvnr+3) ; (* set new drive D *)
INCL(DriveBits,drvnr+4) ; (* set new drive E *)
INCL(DriveBits,drvnr+5) ; (* set new drive F *)
networkconnect := FALSE;
gotframe := FALSE;
framebufferfull := FALSE;
charcount:=0;
SIZEframe:=TSIZE(frame);
SIZEframecmd:=TSIZE(framecmd);
rframeptr := ADR(rframe);
framecmdptr:=ADR(rframe);
sframeptr := ADR(sframe);
CODE(RTS) ; (* code to return to calling BIOS function *)
END InstallVectors ;
PROCEDURE waitcts(what: BOOLEAN); (* wait for cleartosend state *)
BEGIN
IF what THEN
REPEAT
nrecframe;
Nwait(event);
HandleEvents();
IF R>retry THEN
networkerror:=TRUE;
RETURN; (* trouble *)
END;
UNTIL cleartosend;
RETURN;
ELSE
LOOP
nrecframe;
Nwait(event);
IF (NOT cleartosend) THEN EXIT END;
HandleEvents();
IF R>retry THEN
networkerror:=TRUE;
RETURN; (* trouble *)
END;
END; (* loop *)
IF trace THEN BConOut(CON,"N") END;
HandleEvents();
END;
END waitcts;
(* request for data from remote hosts disk drives and system *)
(* what wanted in command, the correct reply in reply, data in f *)
PROCEDURE getfromremote(command, reply: DataKind; VAR f: frame): BOOLEAN;
BEGIN
IF (NOT C.networkactive) THEN RETURN FALSE END; (* error *)
networkerror:=FALSE;
R:=0;
StartTimer;
IF trace THEN BConOut(CON,"A") END;
f.kind:=data;
f.cmd:=command;
waitcts(TRUE);
IF networkerror THEN RETURN FALSE END;
IF trace THEN BConOut(CON,"B") END;
SFRAME:=f;
requesttosend:=TRUE;
waitcts(FALSE);
IF networkerror THEN RETURN FALSE END;
IF trace THEN BConOut(CON,"C") END;
REPEAT
nrecframe;
Nwait(event);
HandleEvents();
IF R>retry THEN networkerror:=TRUE END;
IF networkerror THEN RETURN FALSE END;
UNTIL framewaiting AND (RFRAME.cmd=reply);
IF trace THEN BConOut(CON,"D") END;
f:=RFRAME;
f.rw:=5;
framewaiting:=FALSE;
sendtoremote(ack,reply,f); (* send ack for reply *)
IF networkerror THEN RETURN FALSE END;
IF trace THEN BConOut(CON,"Z") END;
RETURN TRUE;
END getfromremote;
PROCEDURE sendtoremote(type: FrameKind; command: DataKind;VAR f: frame);
BEGIN
IF trace THEN BConOut(CON,"T") END;
f.kind:=type;
f.cmd:=command;
IF debug THEN cleartosend:=TRUE END; (* so we can send in loop *)
waitcts(TRUE);
IF trace THEN BConOut(CON,"1") END;
SFRAME:=f;
requesttosend:=TRUE;
waitcts(FALSE);
IF trace THEN BConOut(CON,"2") END;
IF SFRAME.kind=ack THEN cleartosend:=TRUE END;
END sendtoremote;
PROCEDURE senddata;
BEGIN
SFRAME.seq:=C.nextframetosend;
SFRAME.ack:=1-C.frameexpected;
sendf(SFRAME);
IF (SFRAME.kind#ack) AND (SFRAME.kind#resetreq) THEN
StartTimer; (* set timer to wait for frame ack from remote host *)
END;
END senddata;
(*$P+ *)
PROCEDURE sendf(VAR f: frame);
BEGIN
sframe:=f;
sframe.cksum:=0;
IF ((sframe.cmd=rdrwabsconf) AND ((sframe.rw=0) OR (sframe.rw=2))) OR ((sframe.cmd=rdrwabsreq) AND ((sframe.rw=1) OR (sframe.rw=3))) THEN
sndframesize:=SIZEframe;
sframe.syn := SYN ;
sframe.stx := STX ;
sframe.user := USER ;
shortframe:=FALSE;
IF trace THEN BConOut(CON,":") END;
ELSE
sndframesize:=SIZEframecmd;
sframe.syn := SYN ;
sframe.stx := SOH ;
framecmdptr1:=ADR(sframe);
framecmdptr1^.user := USER ;
shortframe:=TRUE;
IF trace THEN BConOut(CON,".") END;
END;
FOR i1:=0 TO sndframesize-5 DO (* compute checksum *)
sframe.cksum:=sframe.cksum+CARDINAL(sframeptr^[i1])
END;
IF shortframe THEN framecmdptr1^.cksum:=sframe.cksum END;
FOR i1:=0 TO sndframesize-1 DO (* send frame *)
REPEAT
nrecframe;
UNTIL BCosStat(netdevice);
BConOut(netdevice,CHAR(sframeptr^[i1]));
END;
END sendf;
(*$P- *)
PROCEDURE gettime;
BEGIN
clock:=hz200 DIV 200;
CODE(RTS);
END gettime;
(*$P+ *)
PROCEDURE getf(VAR f: frame);
BEGIN
f:=rframe;
framebufferfull:=FALSE;
END getf;
PROCEDURE StartTimer;
BEGIN
SuperExec(gettime);
timestart:=clock; (* set to time in seconds *)
timer:=TRUE; (* test *)
timefortimeout:=timestart;
IncTime(timefortimeout,2);
END StartTimer;
PROCEDURE IncTime(VAR t : LONGCARD; c: CARDINAL);
BEGIN
IF c<1 THEN RETURN END;
t:=t+LONGCARD(c);
END IncTime;
PROCEDURE TimeOut(): BOOLEAN;
BEGIN
IF (NOT timer) THEN RETURN FALSE END;
SuperExec(gettime);
timeouttime:=clock;
SETREG(0,timeouttime);
CODE(0280H,0,0FFFFH);
timeouttime:=LONGCARD(REGISTER(0));
IF timeouttime>timefortimeout THEN
StartTimer;
RETURN TRUE;
END;
RETURN FALSE;
END TimeOut;
PROCEDURE Nwait(VAR e: evtype);
BEGIN
IF requesttosend AND cleartosend THEN
e:=hostready;
requesttosend:=FALSE;
cleartosend:=FALSE;
RETURN;
END;
IF C.sendreset THEN
e:=reset;
END;
IF framebufferfull THEN
cksum:=0;
FOR i2:=0 TO recframesize-5 DO
cksum:=cksum+CARDINAL(rframeptr^[i2])
END;
IF (cksum=rframe.cksum) THEN
e:=framearrival;
INC(R);
ELSE
e:=cksumerr;
framebufferfull:=FALSE;
IF trace THEN BConOut(CON,"U") END;
END;
RETURN;
END;
nrecframe;
IF TimeOut() THEN
e:=timeout;
INC(R);
END; (* so sorry no frame ack *)
END Nwait;
PROCEDURE ToHost(VAR f: frame);
BEGIN
IF trace THEN BConOut(CON,"H") END;
IF f.kind=callreq THEN
framewaiting:=FALSE;
RETURN;
END;
IF f.kind=clearreq THEN
framewaiting:=FALSE;
RETURN;
END;
IF f.kind=diag THEN
framewaiting:=FALSE;
RETURN;
END;
IF f.kind=data THEN
IF f.cmd=rdmediareq THEN
IF trace THEN BConOut(CON,"M") END;
framewaiting:=FALSE;
nframe2.d0:=LONGCARD(MediaChange(CARDINAL(f.d0)));
sendtoremote(data,rdmediaconf,nframe2);
RETURN;
END;
IF f.cmd=rdbpbreq THEN
IF trace THEN BConOut(CON,"P") END;
framewaiting:=FALSE;
nframe2.d0:=LONGCARD(GetBPB(CARDINAL(f.d0)));
bpbptr:=ADDRESS(nframe2.d0);
nbpbptr:=ADR(nframe2.info);
FOR i:=0 TO TSIZE(BPB)-1 DO
nbpbptr^[i]:=bpbptr^[i];
END;
sendtoremote(data,rdbpbconf,nframe2);
RETURN;
END;
IF f.cmd=rdrwabsreq THEN
IF trace THEN BConOut(CON,"W") END;
framewaiting:=FALSE;
nframe2.d0:=LONGCARD(RWAbs(RW(f.rw),ADR(f.info),1,f.recno,
CARDINAL(f.d0)));
IF (f.rw=0) OR (f.rw=2) THEN
nframe2.rw:=f.rw;
nframe2.info:=f.info; (* if rec get buffer to send *)
END;
sendtoremote(data,rdrwabsconf,nframe2);
RETURN;
END;
END;
END ToHost;
PROCEDURE HandleEvents();
BEGIN
IF event=hostready THEN
event:=nothing;
IF trace THEN BConOut(CON,"S") END;
senddata;
END;
IF event=reset THEN
IF trace THEN BConOut(CON,"I") END;
charcount:=0;
R:=0;
gotframe:=FALSE;
framebufferfull:=FALSE;
FOR d:=0 TO 5 DO
gotmediach[d]:=FALSE;
gotbpb[d]:=FALSE;
END;
C.nextframetosend:=0;
C.frameexpected:=0;
cleartosend:=TRUE;
requesttosend:=FALSE;
framewaiting:=FALSE;
timer:=FALSE;
C.sendreset:=FALSE;
event:=nothing;
SFRAME.kind:=resetreq;
senddata;
END;
IF event=framearrival THEN
event:=nothing;
IF (rframe.kind=ack) OR (rframe.kind=resetreq) THEN
framewaiting:=FALSE
END;
IF trace AND (NOT framewaiting) THEN BConOut(CON,"F") END;
IF (NOT framewaiting) THEN getf(RFRAME) END;
framebufferfull:=FALSE;
IF (RFRAME.ack=C.nextframetosend) OR debug THEN
IF trace THEN BConOut(CON,"K") END;
cleartosend:=TRUE;
StartTimer;
R:=0;
timer:=FALSE;
inc(C.nextframetosend);
END;
IF (RFRAME.seq=C.frameexpected) OR debug THEN
IF trace THEN BConOut(CON,"E") END;
IF RFRAME.kind#ack THEN (* try to exec command *)
inc(C.frameexpected);
framewaiting:=TRUE;
R:=0;
ToHost(RFRAME);
END;
END;
IF RFRAME.kind=resetreq THEN
IF trace THEN BConOut(CON,"*") END;
charcount:=0;
gotframe:=FALSE;
framebufferfull:=FALSE;
C.nextframetosend:=0;
C.frameexpected:=0;
FOR d:=0 TO 5 DO
gotmediach[d]:=FALSE;
gotbpb[d]:=FALSE;
END;
cleartosend:=TRUE;
requesttosend:=FALSE;
framewaiting:=FALSE;
timer:=FALSE;
C.sendreset:=FALSE;
event:=nothing;
BConOut(CON,BEL);
BConOut(CON,BEL);
END;
END;
SFRAME.seq:=C.nextframetosend;
SFRAME.ack:=1-C.frameexpected;
IF event=timeout THEN
event:=nothing;
IF trace THEN BConOut(CON,"R") END;
sendf(SFRAME);
framewaiting:=FALSE;
END;
END HandleEvents;
PROCEDURE recframe;
BEGIN
nrecframe;
Nwait(event);
HandleEvents();
END recframe;
PROCEDURE initnetwork(port: Device);
BEGIN
netdevice:=port;
IF Initialise(port) THEN
charcount:=0;
gotframe:=FALSE;
framebufferfull:=FALSE;
C.nextframetosend:=0;
C.frameexpected:=0;
FOR d:=0 TO 5 DO
gotmediach[d]:=FALSE;
gotbpb[d]:=FALSE;
END;
cleartosend:=TRUE;
requesttosend:=FALSE;
framewaiting:=FALSE;
timer:=FALSE;
C.sendreset:=FALSE;
event:=nothing;
C.networkactive:=TRUE;
IF NOT installed THEN
SuperExec(PROC(InstallVectors)) ; (* install the NETWORK *)
installed:=TRUE;
END;
END ;
END initnetwork;
PROCEDURE networkoff;
BEGIN
C.networkactive:=FALSE;
END networkoff;
PROCEDURE networkon;
BEGIN
C.networkactive:=TRUE;
END networkon;
BEGIN
END NETWORK.