{ ************************************************************* } { Program: OMNIDIAG } { Author: Phil Belanger } { Date: 11/05/81 } { Purpose: This program is a diagnostic tool for Omninet. } { It can be used to verify that a Transporter is function-} { ing properly by sending each command individually. } { OMNIDIAG can also be used to set up complicated } { experiments with multiple stations... This version of } { the program is intended for internal use at Corvus and } { by Omninet Licensees... } { } { UNITs used: } { CCDefn - for BYTE definition etc... } { ccOTCio - provides a Pascal interface to the Transporter} { CCCRTIO - used for input with defaults etc... } { hexout - for hex dumps...... } { LABELIO - to use the softkeys } { windowio - to create separate windows } { } { Revision History: } { 0.0 - ported Apple version 2.5 to Star 1/14/82 } { 0.1 - made changes for our screen and keyboard 3/24/82 } { 1.0 - Major changes to utilize the Concept's full power } { added interrupts, windows, and softkeys.... 4/5/82 } { 1.1 - bug fixes... sendstat.... } { 1.2 - attempt to make receives reentrant } { 1.3 - big changes... make it work with new } { reentrant UNIT 9/3/82 } { 1.4 - use interrupts on sends..... } { check for command pending error 9/5/82 } { 1.5 - double buffer sends 9/14/82 } { 1.6 - changes to work with queued driver 9/15/82 } { 1.7 - try until not EntInUse in getpacket 9/24/82 } { } { 2.0 - make it work with new TRANSCMDS unit 2/12/83 } { - also assure compatibility with CCOS v 1.1a } { 2.1 - re arrange display format so that OD will 2/21/83 } { work with the enhanced character set } { PHB } { 3.0 - major change -make it work with CCOS 1.2 2/29/83 } { - the major change is useing ccOCTio unit } { - instead of TRANSCMDS unit } { - the new OD will find out transporter version } { - up to T9.B } { WL } { ************************************************************* } {$P} PROGRAM omnidiag; {$R-} {$I-} { *********************************************************** } { Corvus Systems, Inc. Proprietary Information. } { Unauthorized use or disclosure is prohibited. } { } { Copyright 1983 by Corvus Systems, Inc. } { *********************************************************** } USES {$U /ccutil/cclib} CCDEFN, CCCRTIO, CCLBLIO, CCWNDIO, CCHEXOUT, CCOTCIO; CONST odvers = '[3.0]'; MaxBufs = 10; MaxRetries = 10; BufSize = 520; { big enough to simulate disk commands} HdrLen = 16; { bigger than the biggest Constellation header } { indexes into the array of counters } SAT = 11; { sends attempted } SOK = 12; { successful sends } SGU = 13; { give ups } STL = 14; { sent a packet which was too long } SNS = 15; { socket not setup... sent to unitied socket } SHE = 16; { header length mismatch } MaxCount = 16; {$P} TYPE pBUFFER = ^BUFFER; pMCB = ^MCB; SOCKSTATE = (NoSock, NoBuf, RcvSet); ODRES = RECORD RES: TCrsltRcd; HDR: ARRAY[1..HdrLen] OF BYTE; END; BUFFER = RECORD CASE BOOLEAN OF TRUE: (BYT: ARRAY[1..BufSize] OF BYTE); FALSE: (CHR: PACKED ARRAY[1..BufSize] OF CHAR); END; MCB = RECORD { Message Control Block } NEXT: pMCB; ID: INTEGER; PTRS: TCParmBlk; END; EXCHANGE = RECORD CURMCB: pMCB; COUNT: LONGINT; LEND: INTEGER; LENH: BYTE; LASTSRC: BYTE; LASTID: INTEGER; STATE: SOCKSTATE; END; TRIX = RECORD CASE INTEGER OF 1: (LNG: LONGINT); 2: (PTR: ^BYTE); 3: (ARR: ARRAY[0..3] OF BYTE); END; {$P} VAR counts: ARRAY[0..MaxCount] OF LONGINT; { OD counters } socktbl: ARRAY[1..4] OF EXCHANGE; { socket table } restbl: ARRAY[1..MaxBufs] OF ODRES; { result table } buftbl: ARRAY[1..MaxBufs] OF BUFFER; { buffer table } gotrecv: ARRAY[0..4] OF BOOLEAN; { true if a new message has come in } newcmd: BOOLEAN; { true if a command has been entered at the keyboard } done: BOOLEAN; { True if the program is over } verbose: BOOLEAN; { true if we are in verbose mode } omode: BOOLEAN; { true if we are in Omninet single command mode } socknum: INTEGER; { the last socket number which received a message } cmdchar: CHAR; { the current command character } hostnum: INTEGER; { our host number } cntwind: WNDRCD; { the window record representing the counter area } sndwind: WNDRCD; whowind: WNDRCD; ramwind: WNDRCD; genwind: WNDRCD; sparmwind: WNDRCD; rcvwind: WNDRCD; { the receive status window } tcdebug: BOOLEAN; { True if we are in tcdebug mode } deb: BOOLEAN; firstsend: BOOLEAN; { True if this is the first send... } lastsend: BOOLEAN; gotsend: BOOLEAN; { True if we got a send interrupt } sending: BOOLEAN; { True if we are looping sending... } ssock: INTEGER; { send destination socket } dest: INTEGER; { send destination host number } sdl: INTEGER; { send data length } shl: BYTE; { send header length } smsg: pMCB; { points at a list of send message control blocks } numsend: INTEGER; { number of sends to try... } rsock: INTEGER; { current receive socket } rdl: INTEGER; { receive data length } rhl: BYTE; { receive header length } delay: INTEGER; ii, ior: INTEGER; FUNCTION pOScurWnd: pWndRcd; EXTERNAL; FUNCTION unsigned(b: BYTE): INTEGER; FORWARD; {$P} {$I OD.SCREEN.TEXT } {$I OD.UTILS.TEXT } { *********************************************************** } { getpacket - get the packet which just came in on socket sn } { Update the receive status for socket sn and attempt to set } { up a new receive on that socket. } { General Receive Interrupt Routine } { *********************************************************** } PROCEDURE getpacket(sn: INTEGER; rslt: TCrsltRcd); VAR x: INTEGER; BEGIN WITH socktbl[sn] DO IF (STATE <> NoSock) AND (rslt.RCODE = OkCode) THEN BEGIN LASTID := CURMCB^.ID; COUNT := COUNT + 1; LASTSRC := rslt.SOURC; CURMCB := CURMCB^.NEXT; REPEAT TCinitBlk (CURMCB^.PTRS,CURMCB^.PTRS.PRSLT,CURMCB^.PTRS.PBUFF,CURMCB^.PTRS.PPROC); x := TCsetRecv (CURMCB^.PTRS, sn, LEND, LENH); CASE x OF OkCode: WITH CURMCB^.PTRS.PRSLT^ DO CASE unsigned(RCODE) OF CmdAcpt: STATE := RcvSet; InUse, BadSock: BEGIN cmdstat(unsigned(RCODE)); STATE := NoBuf END; Waiting: fatal('In getpacket, result code is still FF......'); OkCode: STATE := NoBuf; END; {CASE} TCQueued: BEGIN END; { do nothing! STATE is really NoBuf, but we won't know when it changes...} TCEntUse: BEGIN { fatal('In getpacket, entry in use...') } END; OTHERWISE: fatal('In getpacket, Transporter not responding...'); END {CASE} UNTIL x <> TcEntUse; gotrecv[0] := TRUE; { got something } gotrecv[sn] := TRUE; {... on socket sn } END; END; {$P} PROCEDURE rsock1(err: INTEGER; s: INTEGER; r: pTCrsltRcd; b: pTCbuffer; p: pTCparmBlk); BEGIN IF err <> 0 THEN fatal('Last receive on sock 1 didn`t work!'); getpacket(1, r^); END; PROCEDURE rsock2(err: INTEGER; s: INTEGER; r: pTCrsltRcd; b: pTCbuffer; p: pTCparmBlk); BEGIN IF err <> 0 THEN fatal('Last receive on sock 2 didn`t work!'); getpacket(2, r^); END; PROCEDURE rsock3(err: INTEGER; s: INTEGER; r: pTCrsltRcd; b: pTCbuffer; p: pTCparmblk); BEGIN IF err <> 0 THEN fatal('Last receive on sock 3 didn`t work!'); getpacket(3, r^); END; PROCEDURE rsock4(err: INTEGER; s: INTEGER; r: pTCrsltRcd; b: pTCbuffer; p: pTCparmBlk); BEGIN IF err <> 0 THEN fatal('Last receive on sock 4 didn`t work!'); getpacket(4, r^); END; {$P} { *************************************************************** } { peekcmd - get parms from user and transpeek or transpoke into Transporter } { *************************************************************** } PROCEDURE peekpoke; VAR tcp: TCparmBlk; ch: CHAR; li: LONGINT; i, adr, tcode: INTEGER; val: INTEGER; BEGIN ii := winselect(genwind); CRT(EraseAll); inverson; printmsg(0, 0, 'Peek/Poke into the Transporter memory:'); inversoff; printmsg(0, 1, 'Peek/Poke what address? '); li := $E6; IF getlongnum(li) <> Normal THEN EXIT(peekpoke); adr := ORD(li); printmsg(0, 2, 'P)eek or W)rite? P'); CRT(CursorLeft); ch := GETBYTE; IF ch = 'W' THEN {this is a transpoke command} BEGIN i := 0; printmsg(0, 3, 'Poke what value? '); IF getnum(i) <> Normal THEN EXIT(peekpoke); val := ORD(i); IF TCpokeTrans (adr, val, tcode) <> 0 THEN fatal('Poke failed...'); cmdstat(tcode); END ELSE BEGIN IF TCpeekTrans (adr,val) <> 0 THEN fatal('Peek failed...'); printmsg(0, 3, '['); puthexword(adr); write('] = '); puthexbyte(val); END; END; {$P} { ********************************************************************* } { initcmd - is executed when someone enters the I command from keyboard } { ********************************************************************* } PROCEDURE initcmd; VAR i: INTEGER; b: INTEGER; BEGIN ii := winselect(genwind); CRT(EraseAll); printmsg(0,0,'Initializing Transporter...'); IF TCinitTrans(b) <> 0 THEN fatal('Transporter not responding...') ELSE hostnum := b; printmsg(0, 1, ' This is host number '); writeln(hostnum, '.'); FOR i := 1 TO 4 DO { sockets were re initialized so update display } BEGIN socktbl[i].COUNT := 0; socktbl[i].STATE := NoSock; rcvstat(i, true); END; END; { *********************************************** } { endcmd - stop receiving on the specified socket } { *********************************************** } PROCEDURE endcmd; BEGIN ii := winselect(genwind); CRT(EraseAll); printmsg(0, 0, 'Stop receiving.'); printmsg(0, 1, 'Stop receiving on which socket? '); getsock(rsock); IF rsock < 0 THEN BEGIN rsock := 3; EXIT(endcmd) END; IF TCendrecv(rsock, ii) <> 0 THEN { not checking for transporter error } BEGIN fatal('Endrecv failed...'); EXIT(endcmd); END; socktbl[rsock].STATE := NoSock; rcvstat(rsock, true); END; {$P} { general purpose message sender... } PROCEDURE sendum; VAR sendcode, i: INTEGER; BEGIN TCinitBlk (smsg^.NEXT^.PTRS,smsg^.NEXT^.PTRS.PRSLT,smsg^.NEXT^.PTRS.PBUFF,smsg^.NEXT^.PTRS.PPROC); FOR i := 0 TO delay DO; {nothing} SENDCODE := TCsndMesg( smsg^.NEXT^.PTRS ,ssock, sdl, shl, dest); CASE sendcode OF OkCode, TCQueued: IF numsend <> 0 THEN BEGIN numsend := numsend - 1; IF numsend = 0 THEN lastsend := TRUE; END; TCEntUse: fatal('In Sendum... Entry in use....... '); OTHERWISE: fatal('In SENDUM... Transporter not responding.'); END; {CASE} END; { *************************************************************************** } { sendint - interrupt routine for sends... increment counters and notify main } { level that we got a send interrupt } { *************************************************************************** } PROCEDURE sendint(err: INTEGER; s: INTEGER; r: pTCrsltrcd; b: pTCbuffer; p: pTCparmBlk ); BEGIN IF err <> 0 THEN fatal('The last send was queued and failed...'); sendcnts(unsigned(smsg^.NEXT^.PTRS.pRslt^.RCODE)); smsg := smsg^.NEXT; gotsend := TRUE; END; { ******************** } { againcmd - repeats the last send command n times } { ******************** } PROCEDURE againcmd; BEGIN ii := winselect(genwind); CRT(EraseAll); printmsg(0,0, 'Send the last message again.'); printmsg(0,1, 'Send it how many times? '); IF getnum(numsend) <> Normal THEN EXIT(againcmd); showsendparms; sendum; END; {$P} { ****************************************************************** } { sendcmd - prompt the user for parameters and execute a transporter } { sendmsg command } { ****************************************************************** } PROCEDURE sendcmd; VAR i: INTEGER; BEGIN ii := winselect(genwind); CRT(EraseAll); IF sending THEN BEGIN printmsg(0,0, 'Stop Sending...'); numsend := 1; {this turns off sending...} EXIT(sendcmd); END; inverson; printmsg(0, 0, 'Send a Packet:'); inversoff; printmsg(0, 1, 'Send to what host? '); i := dest; IF getnum(i) <> Normal THEN EXIT(sendcmd); dest := ORD(i); printmsg(0,2, 'Send to which socket? '); getsock(ssock); IF ssock < 0 THEN BEGIN ssock := 3; EXIT(sendcmd) END; gethdrlen(shl, ssock); IF shl < 0 THEN BEGIN shl := HdrLen; EXIT(sendcmd) END; printmsg(0, 4, 'Send how many bytes? '); IF getnum(sdl) <> Normal THEN EXIT(sendcmd); IF sdl > BufSize THEN sdl := BufSize; IF shl > 0 THEN { must fill both headers/buffers now that we are double buffered } BEGIN hdrfill(restbl[9], shl); restbl[10] := restbl[9]; END; IF sdl > 0 THEN BEGIN buffill(buftbl[9], sdl); buftbl[10] := buftbl[9]; END; printmsg(0,12, 'Send how many? ( 0=forever ) '); IF getnum(numsend) <> Normal THEN EXIT(sendcmd); showsendparms; sending := TRUE; sendum; END; {$P} { ******************************************************************** } { rcvcmd - set up a receive... gets the parameter values from keyboard } { ******************************************************************** } PROCEDURE rcvcmd; VAR i: INTEGER; BEGIN i := winselect(genwind); CRT(EraseAll); printmsg(0, 0, 'Set Up a Receive:'); printmsg(0, 1, 'Receive on which socket? '); i := rsock; REPEAT { find a likely candidate for rsock default } i := (i MOD 4) + 1; IF socktbl[i].STATE = NoSock THEN rsock := i; UNTIL i = rsock; getsock(rsock); IF rsock < 0 THEN BEGIN rsock := 3; EXIT(rcvcmd); END; printmsg(0, 2, 'What is the maximum length you wish to receive? '); IF getnum(rdl) <> Normal THEN EXIT(rcvcmd); IF rdl>Bufsize THEN rdl := Bufsize; gethdrlen(rhl, rsock); IF rhl < 0 THEN BEGIN rhl := HdrLen; EXIT(rcvcmd) END; WITH socktbl[rsock] DO BEGIN LEND := rdl; LENH := rhl; TCinitBlk (CURMCB^.PTRS,CURMCB^.PTRS.PRSLT,CURMCB^.PTRS.PBUFF,CURMCB^.PTRS.PPROC); IF TCsetRecv(CURMCB^.PTRS, rsock, LEND, LENH) <> 0 THEN fatal('Receive setup failed...'); i := unsigned(CURMCB^.PTRS.pRslt^.RCODE); CASE i OF OkCode: STATE := NoBuf; CmdAcpt: STATE := RcvSet; InUse: BEGIN cmdstat(i); EXIT(rcvcmd); END; END; COUNT := 0; END; { with} rcvstat(rsock, True); i := winsystem(WsysCmd); printmsg(0, 0, 'Command Status ===> Receive Setup Successful'); END; {$P} { *************************************************************** } { recvs - does the receive oriented commands... } { *************************************************************** } PROCEDURE recvs; BEGIN CASE GETBYTE OF 'E': endcmd; 'R', ' ': rcvcmd; END; END; PROCEDURE dolabels; VAR i: INTEGER; BEGIN LblsInit; { clear the softkey labels } i := LblSet(0, 'Receive', 'RR'); i := LblSet(1, ' Send', 'S'); i := LblSet(2, ' Echo', 'E'); i := LblSet(3, ' Init', 'I'); i := LblSet(4, 'EndRecv', 'RE'); i := LblSet(5, ' Peek', 'P'); i := LblSet(6, ' Poke', 'P'); i := LblSet(7, ' Who', 'W'); i := LblSet(8, 'Again', 'A'); i := LblSet(9, ' Exit', 'Q'); i := LblSet(20, ' Dump', 'D'); i := LblSet(21, ' Fill', 'F'); i := LblSet(22, 'Delay', 'MN'); i := LblSet(23, '6801 RAM', 'MR'); i := LblSet(24, 'ZeroCnt', 'Z'); i := LblSet(25, 'ODdebug', 'MD'); i := LblSet(26, 'TCdebug', 'MT'); i := LblSet(28, ' Help', 'H'); i := LblSet(29, ' Exit', 'Q'); LblsOn; END; {$P} PROCEDURE initdiag; CONST Eighta = 138; SixFour = 100; hF800 = -2048; VAR mp: pMCB; ch: CHAR; tv, i, j, k, c : INTEGER; BEGIN cchexinit; {initialize hexout unit } CCCRTIOINIT; { initialize the CCCRTIO unit } CCWndioinit; { ....the window unit } cclblioinit; ccOTCioInit; { initialize the CCOCTIO unit } Crtsdef := TRUE; {turn on string defaults } CRTTahd := TRUE; tcdebug := False; deb := FALSE; dolabels; delay := 0; horizcreate; { create the windows for the horizontal screen } FOR i := 0 TO 4 DO gotrecv[i] := FALSE; j := 0; FOR i := 1 TO 4 DO BEGIN WITH socktbl[i] DO BEGIN NEW(mp); CURMCB := mp; NEW(mp); CURMCB^.NEXT := mp; mp^.NEXT := CURMCB; { create a circular list } mp := CURMCB; REPEAT j := j + 1; WITH mp^, mp^.PTRS DO BEGIN ID := j; pRslt := @restbl[j]; pBuff := @buftbl[j]; CASE i OF 1: pPROC := @rsock1; 2: pPROC := @rsock2; 3: pPROC := @rsock3; 4: pPROC := @rsock4; END; {Case} END; {WITH mp....} mp := mp^.NEXT UNTIL mp = CURMCB; COUNT := 0; STATE := NoSock; END; {WITH} END; { continued on next page... } {$P} { initdiag continued... } NEW(mp); smsg := mp; NEW(mp); smsg^.NEXT := mp; mp^.NEXT := smsg; FOR i := 1 TO 2 DO BEGIN smsg := smsg^.NEXT; WITH smsg^, smsg^.PTRS DO {initialize send message control point } BEGIN ID := j + i; pRslt := @restbl[ID]; pBuff := @buftbl[ID]; pPROC := @sendint; END; END; sdl := BufSize; shl := 0; ssock := 2; dest := 63; rdl := BufSize; rhl := 0; rsock := 2; sending := FALSE; lastsend := FALSE; gotsend := FALSE; numsend := 0; omode := TRUE; newcmd := FALSE; done := FALSE; verbose := TRUE; socknum := 1; i := TCwhoami(hostnum); { find out the host number 0.5 } IF i <> 0 THEN fatal('Transporter not responding!!!'); CRT(EraseAll); inverson; printmsg(0,0,' '); printmsg(0,1,' Omninet Diagnostic V'); write(odvers); k := TCpeekTrans( hF800, c); tv := unsigned(c); CASE tv OF SixFour: printmsg(53,1, 'T6.4'); EightA: printmsg(53,1, 'T8.A'); 139: printmsg(53,1, 'T8.B'); { 139 = $8B } 155: printmsg(53,1, 'T9.B'); { 155 = $9B } END; printmsg(74, 1, 'Host Number = '); write(hostnum:-2); inversoff; initrcvwnd; initcounts; END; {$P} { *************************************************** } { echocmd - send an echo packet to the specified host } { *************************************************** } PROCEDURE echocmd; VAR tcode, dest: INTEGER; BEGIN ii := winselect(genwind); CRT(EraseAll); printmsg(0,0, 'Echo command:'); printmsg(0,1, 'Send echo to what host? '); dest := 0; IF getnum(dest) <> Normal THEN EXIT(echocmd); IF TCechoTrans(ORD(dest),tcode) <> 0 THEN fatal('Unable to do an echo command.'); cmdstat(tcode); END; { ******************************************************** } { miscmds - do the miscellaneous commands.... } { ******************************************************** } PROCEDURE miscmds; BEGIN CASE GETBYTE OF 'D': deb := NOT deb; 'T': tcdebug := NOT tcdebug; 'N': delaycmd; 'R', ' ': ramdump; 'V': verbose := NOT verbose; END; END; {$P} { *********************************************************** } { dump the contents of a buffer, header or any memory loc... } { *********************************************************** } PROCEDURE dump; VAR ch: CHAR; BEGIN ii := winselect(genwind); CRT(EraseAll); write('Display M)emory, B)uffer or H)eader? B'); CRT(CursorLeft); ch := GETBYTE; ior := winselect(genwind); CRT(EraseAll); CASE ch OF 'M': mdump; 'H': hdump; 'B', ' ': bdump; END; {CASE} END; {$P} PROCEDURE fill; VAR bp: pBUFFER; ch: CHAR; adr: LONGINT; id, ln: INTEGER; BEGIN id := winselect(genwind); CRT(EraseAll); printmsg(0, 2, 'Fill a B)uffer H)eader or M)emory? B'); CRT(CursorLeft); ch := GETBYTE; printmsg(0,10, 'Hit to quit filling...'); CASE ch OF ' ', 'B': BEGIN printmsg(0,3, 'Fill which buffer? '); id := 7; IF getnum(id) <> Normal THEN EXIT(fill); IF id> MaxBufs THEN EXIT(fill); ln := BufSize; {length is a VAR parameter... } buffill(buftbl[id], ln); END; 'H': BEGIN printmsg(0,3, 'Fill which header? '); id := 0; IF getnum(id) <> Normal THEN EXIT(fill); IF id > MaxBufs THEN EXIT(fill); hdrfill(restbl[id], HdrLen); END; 'M': BEGIN printmsg(0,3, 'Fill starting at what location? '); adr := $90000; IF getlongnum(adr) <> Normal THEN EXIT(fill); bp := POINTER(adr); printmsg(0,4, 'Fill how many bytes? '); ln := 1; IF getnum(ln) <> Normal THEN EXIT(fill); buffill(bp^, ln); END; END; {CASE} END; {$P} PROCEDURE whocmd; VAR whoset: TCHOSTSET; x,y,i: INTEGER; BEGIN i := winselect(whowind); CRT(EraseAll); inverson; printmsg(0,0,' '); printmsg(0,1, ' Active Omninet hosts: '); inversoff; i := TCnetMap(whoset); x := 2; y := 2; FOR i := 0 TO 63 DO BEGIN IF i IN whoset THEN BEGIN GOTOXY(x,y); write(i:3); y := y+1; IF y > 10 THEN BEGIN y := 2; x := x +4; END; END; END; END; {$P} { *********************************************************** } { shosends - display send stats and do new send if necessary } { *********************************************************** } PROCEDURE shosends; VAR ok: BOOLEAN; BEGIN gotsend := FALSE; sendstat(firstsend); IF firstsend THEN BEGIN invertwin(sparmwind); firstsend := FALSE; END; IF lastsend THEN BEGIN invertwin(sparmwind); sending := FALSE; shocounts; lastsend := FALSE; prompt; END; IF (sending) AND (NOT lastsend) THEN sendum; END; PROCEDURE cleanscreen; VAR i: INTEGER; BEGIN i := winselect(genwind); CRT(EraseAll); shocounts; sendstat(TRUE); FOR i := 1 TO 4 DO IF socktbl[i].STATE <> NoSock THEN rcvstat(i, TRUE); END; {$P} { ************************* } { doit - do the command selected by cmd } { ************************* } PROCEDURE doit(cmd: CHAR); BEGIN ior := winsystem(WsysCmd); printmsg(0,0, ''); newcmd := FALSE; CASE cmd OF 'A': againcmd; 'C': shocounts; 'D': dump; 'E': echocmd; 'F': fill; 'H': help; 'I': initcmd{}; 'M': miscmds{}; 'O': omode := NOT omode; 'P': peekpoke{}; 'Q': done := TRUE; 'R': recvs{}; 'S': sendcmd{}; 'V': verbose := NOT verbose; 'W': whocmd; 'Z': BEGIN zerocnts; cleanscreen; END; ' ': cleanscreen; END; {CASE} UNITCLEAR(1); { 2.2 } prompt; END; PROCEDURE shorecvs; VAR i: INTEGER; BEGIN gotrecv[0] := FALSE; FOR i := 1 TO 4 DO IF gotrecv[i] THEN BEGIN gotrecv[i] := FALSE; rcvstat(i, FALSE); END; END; {$P} PROCEDURE cleanup; VAR i,tcode: INTEGER; BEGIN FOR i := 1 TO 4 DO IF socktbl[i].STATE <> NoSock THEN ii := TCendrecv(i, tcode); i := winsystem(WsysCurr); CRT(EraseAll); i := windelete(genwind); i := windelete(sndwind); i := windelete(whowind); i := windelete(ramwind); i := windelete(sparmwind); i := windelete(rcvwind); i := windelete(cntwind); END; FUNCTION getcommand: CHAR; BEGIN ior := winsystem(WsysCmd); newcmd := TRUE; getcommand := GETBYTE; END; BEGIN { omnidiag main program } CRT(EraseAll); initdiag; prompt; WHILE NOT done DO BEGIN IF gotrecv[0] THEN shorecvs{}; IF gotsend THEN shosends{}; IF newcmd THEN doit(cmdchar); IF UNITBUSY(35) THEN cmdchar := getcommand{}; END; cleanup{}; END. {omnidiag}