-- File: BSPTestTool.mesa, Last Edit: HGM February 9, 1981 7:48 PM DIRECTORY Process USING [Detach, Yield], Storage USING [Node, String, Free, FreeNodeNil, FreeString], String USING [AppendString], System USING [Pulses, GetClockPulses, PulsesToMicroseconds], Time USING [AppendCurrent, Current], Event USING [Item, Reason, AddNotifier], FormSW USING [ ClientItemsProcType, ProcType, AllocateItemDescriptor, newLine, Display, FindItem, CommandItem, BooleanItem, StringItem, NumberItem], MsgSW USING [Post], Put USING [Char, CR, Text, Line, LongDecimal, LongNumber], Tool USING [Create, MakeSWsProc, MakeMsgSW, MakeFormSW, MakeFileSW], ToolWindow USING [TransitionProcType], Window USING [Handle], Stream USING [Handle, PutWord, PutBlock, SendNow, Delete], PupDefs USING [ AppendPupAddress, GetPupAddress, PupNameTrouble, PupPackageMake, PupPackageDestroy, SecondsToTocks], PupStream USING [PupByteStreamCreate, StreamClosing, CloseReason], PupTypes USING [PupAddress, bspTestSoc]; BSPTestTool: PROGRAM IMPORTS Process, Storage, String, System, Time, Event, FormSW, MsgSW, Put, Tool, Stream, PupDefs, PupStream = BEGIN OPEN PupStream, PupTypes; defualtClumpLength: CARDINAL = 1000; -- words defualtNumberOfClumps: CARDINAL = 1000; -- 1 mega word msg, form, log: Window.Handle; eventItem: Event.Item _ [eventMask: 177777B, eventProc: Broom]; -- Be sure to initialize it when it is allocated!!!! data: POINTER TO Data _ NIL; -- NIL when we are inactive Data: TYPE = RECORD [ where: PupAddress _ [[0], [0], PupTypes.bspTestSoc], clumpLength: CARDINAL _ defualtClumpLength, numberOfClumps: CARDINAL _ defualtNumberOfClumps, pleaseStop: BOOLEAN _ FALSE, alignTheFink0: WORD _ NULL, running: BOOLEAN _ FALSE, alignTheFink1: WORD _ NULL, verbose: BOOLEAN _ FALSE, alignTheFink2: WORD _ NULL, sendForever: BOOLEAN _ FALSE, alignTheFink3: WORD _ NULL, forceOutClumps: BOOLEAN _ FALSE, alignTheFink4: WORD _ NULL, sendFirstWord: BOOLEAN _ FALSE, target: STRING _ NULL]; Init: PROCEDURE = BEGIN [] _ Tool.Create[ name: "BSP Tester of February 9, 1981"L, makeSWsProc: MakeSWs, clientTransition: ClientTransition]; Event.AddNotifier[@eventItem]; END; BSPTestOn: PROCEDURE = BEGIN WriteCR[]; IF data.clumpLength ~IN [2..10000) THEN BEGIN MsgSW.Post[msg, "ClumpLength should be between 2 and 10000."L]; RETURN; END; WriteCurrentDateAndTime[]; WriteString[" Sending to "L]; IF ~FindPath[] THEN RETURN; data.running _ TRUE; UpdatePicture[]; Process.Detach[FORK Push[]]; END; BSPTestOff: PROCEDURE = BEGIN data.pleaseStop _ TRUE; WHILE data.running DO Process.Yield[]; ENDLOOP; data.pleaseStop _ FALSE; UpdatePicture[]; END; Finished: PROCEDURE = BEGIN data.running _ FALSE; IF ~data.pleaseStop THEN UpdatePicture[]; END; UpdatePicture: PROCEDURE = BEGIN FormSW.FindItem[form, startIX].flags.invisible _ data.running; FormSW.FindItem[form, stopIX].flags.invisible _ ~data.running; FormSW.FindItem[form, clumpIX].flags.readOnly _ data.running; FormSW.Display[form]; END; FindPath: PROCEDURE RETURNS [BOOLEAN] = BEGIN OPEN data; WriteString[target]; WriteChar['=]; PupDefs.GetPupAddress[ @where, target ! PupDefs.PupNameTrouble => BEGIN MsgSW.Post[msg, e]; WriteLine[e]; GOTO Trouble; END]; PrintPupAddress[where]; WriteLine["."L]; RETURN[TRUE]; EXITS Trouble => RETURN[FALSE]; END; Push: PROCEDURE = BEGIN OPEN data; sh: Stream.Handle; start, stop: LONG CARDINAL; words: LONG CARDINAL _ 0; recent: System.Pulses; startOpen, endOpen, startFirstSend, endFirstSend, startClose, endClose: System.Pulses; buffer: POINTER; hits: CARDINAL _ 0; info: ARRAY CloseReason OF STRING = [localClose: "Closed locally"L, localAbort: "Local Abort"L, remoteClose: "Remote close"L, noRouteToNetwork: "No route to that network"L, transmissionTimeout: "Transmission timeout"L, remoteReject: "Remote reject"L]; WriteString["Clump size is "L]; WriteLongDecimal[clumpLength]; WriteLine[" words."L]; start _ Time.Current[]; startOpen _ System.GetClockPulses[]; sh _ PupByteStreamCreate[ where, PupDefs.SecondsToTocks[10] ! StreamClosing => BEGIN WriteString["Connection failed: "L]; IF text # NIL THEN BEGIN WriteChar['(]; WriteString[text]; WriteString[") "L]; END; WriteLine[info[why]]; GOTO Failed; END]; endOpen _ System.GetClockPulses[]; IF sendFirstWord THEN BEGIN ENABLE StreamClosing => CONTINUE; startFirstSend _ System.GetClockPulses[]; Stream.PutWord[sh, 0]; words _ words + 1; endFirstSend _ System.GetClockPulses[]; END; recent _ System.GetClockPulses[]; buffer _ Storage.Node[clumpLength]; FOR clumps: CARDINAL _ 0, clumps + 1 UNTIL pleaseStop OR (~sendForever AND clumps >= data.numberOfClumps) DO Stream.PutBlock[ sh, [buffer, 0, 2*clumpLength], forceOutClumps ! StreamClosing => BEGIN WriteString["Push Stream closed: "L]; IF text # NIL THEN BEGIN WriteChar['(]; WriteString[text]; WriteString[") "L]; END; WriteLine[info[why]]; GOTO Closed; END]; words _ words + clumpLength; IF verbose THEN BEGIN WriteChar['!]; IF ((hits _ hits + 1) MOD 50) = 0 THEN BEGIN ms: LONG CARDINAL; -- Oh shit. This overflows at a clumpLength of 20000 wrods. fudge: LONG CARDINAL = 100*LONG[16*50]; ms _ System.PulsesToMicroseconds[[System.GetClockPulses[] - recent]]/10000; WriteString[" "L]; WriteLongDecimal[(fudge*clumpLength)/ms]; WriteLine[" bits/sec"L]; recent _ System.GetClockPulses[]; END; END; REPEAT Closed => NULL; ENDLOOP; startClose _ System.GetClockPulses[]; Stream.SendNow[sh ! StreamClosing => CONTINUE]; Stream.Delete[sh]; endClose _ System.GetClockPulses[]; stop _ Time.Current[]; Storage.Free[buffer]; WriteCR[]; WriteLongDecimal[words]; WriteLine[" words sent."L]; IF stop - start > 100 OR words > 100000 THEN BEGIN WriteLongDecimal[16*words/(stop - start)]; END ELSE BEGIN t: System.Pulses _ [endClose - startOpen]; WriteLongDecimal[16*words*1000/(System.PulsesToMicroseconds[t]/1000)]; END; WriteLine[" data bits per second."L]; PrintTiming["Open"L, endOpen, startOpen]; IF sendFirstWord THEN PrintTiming["First Ack"L, endFirstSend, startFirstSend]; PrintTiming["Close"L, endClose, startClose]; IF words < 5000000 THEN PrintTiming["Total"L, endClose, startOpen]; WriteCR[]; Finished[]; EXITS Failed => Finished[]; END; -- IO things WriteChar: PROCEDURE [c: CHARACTER] = BEGIN Put.Char[log, c]; END; WriteCR: PROCEDURE = BEGIN Put.CR[log]; END; WriteString: PROCEDURE [s: STRING] = BEGIN Put.Text[log, s]; END; WriteLine: PROCEDURE [s: STRING] = BEGIN Put.Line[log, s]; END; WriteLongDecimal: PROCEDURE [n: LONG CARDINAL] = BEGIN Put.LongDecimal[log, n]; END; WriteCurrentDateAndTime: PROCEDURE = BEGIN time: STRING = [20]; Time.AppendCurrent[time]; WriteString[time]; END; PrintPupAddress: PROCEDURE [a: PupAddress] = BEGIN temp: STRING = [40]; PupDefs.AppendPupAddress[temp, a]; WriteString[temp]; END; PrintTiming: PROCEDURE [s: STRING, end, start: System.Pulses] = BEGIN t: System.Pulses _ [end - start]; WriteString[s]; WriteString[" took "L]; WriteLongDecimal[System.PulsesToMicroseconds[t]/1000]; WriteLine[" ms."L]; END; Start: FormSW.ProcType = BEGIN BSPTestOn[]; END; Stop: FormSW.ProcType = BEGIN BSPTestOff[]; END; MakeSWs: Tool.MakeSWsProc = BEGIN msg _ Tool.MakeMsgSW[window: window, lines: 5]; form _ Tool.MakeFormSW[window: window, formProc: MakeForm]; log _ Tool.MakeFileSW[window: window, name: "BSPTest.log$"L]; END; startIX: CARDINAL = 0; stopIX: CARDINAL = 1; clumpIX: CARDINAL = 4; MakeForm: FormSW.ClientItemsProcType = BEGIN nParams: CARDINAL = 10; items _ FormSW.AllocateItemDescriptor[nParams]; items[0] _ FormSW.CommandItem[ tag: "Start"L, proc: Start, place: FormSW.newLine]; items[1] _ FormSW.CommandItem[ tag: "Stop"L, proc: Stop, place: FormSW.newLine, invisible: TRUE]; items[2] _ FormSW.BooleanItem[ tag: "Running"L, switch: @data.running, readOnly: TRUE]; items[3] _ FormSW.BooleanItem[tag: "Verbose"L, switch: @data.verbose]; items[4] _ FormSW.BooleanItem[tag: "SendForever"L, switch: @data.sendForever]; items[5] _ FormSW.BooleanItem[ tag: "SendFirstWord"L, switch: @data.sendFirstWord]; items[6] _ FormSW.BooleanItem[ tag: "ForceOutClumps"L, switch: @data.forceOutClumps]; items[7] _ FormSW.NumberItem[ tag: "ClumpLength"L, value: @data.clumpLength, place: FormSW.newLine]; items[8] _ FormSW.NumberItem[ tag: "NumberOfClumps"L, value: @data.numberOfClumps, place: FormSW.newLine]; items[9] _ FormSW.StringItem[ tag: "Target"L, string: @data.target, place: FormSW.newLine]; RETURN[items, TRUE]; END; AlreadyActive: ERROR = CODE; NotActive: ERROR = CODE; ClientTransition: ToolWindow.TransitionProcType = BEGIN SELECT TRUE FROM old = inactive => BEGIN IF data # NIL THEN ERROR AlreadyActive; data _ Storage.Node[SIZE[Data]]; data^ _ []; data.target _ Storage.String[20]; String.AppendString[data.target, "ME"L]; PupDefs.PupPackageMake[]; END; new = inactive => BEGIN IF data = NIL THEN ERROR NotActive; IF data.running THEN BSPTestOff[]; PupDefs.PupPackageDestroy[]; Storage.FreeString[data.target]; data _ Storage.FreeNodeNil[data]; END; ENDCASE; END; Broom: PROCEDURE [why: Event.Reason] = BEGIN SELECT why FROM makeImage, makeCheck => BEGIN IF data = NIL THEN RETURN; IF data.running THEN BSPTestOff[]; PupDefs.PupPackageDestroy[]; END; startImage, restartCheck, continueCheck => BEGIN IF data = NIL THEN RETURN; PupDefs.PupPackageMake[]; END; ENDCASE => NULL; END; -- Main Body Init[]; END.