<> <> <> <> <<>> <<<>>> DIRECTORY BasicTime USING [GMT, Now, Period, Update], IO, MarkerControl USING [ClientProcs, ClientProcsHandle, MarkerStatus], MarkerControlImpl, MarkerControlInternal, PaperHandling USING [BannerMode, PrintOrder], PaperTypes USING [nullDimensions, Paper], PrintingState USING [Type], PrintingTypes USING [Option], PrintQueue USING [Empty, nilQueueObjectHandle, ObjectStatus, QueueObjectHandle, QueueStage, Requeue], Process USING [Detach, MsecToTicks, Pause, Priority, priorityBackground, SecondsToTicks, SetPriority, SetTimeout], PSAsyncMsg USING [PutString], BansheeCounter USING [ForceOut], BansheeEngine USING [GetPaperSize, GetStatus, GetPrintingState, Job, SetJob, SetPrintingState, WaitStatus, WaitPrintingState, JobHandle], BansheeMarkerControl, BansheeStatus USING [Type], Rope USING [ROPE, ToRefText]; BansheeMarkerControlImpl: CEDAR MONITOR LOCKS root IMPORTS root: MarkerControlImpl, --DecomposerControl, -- BansheeCounter, BansheeEngine, BasicTime, IO, MarkerControlInternal, PrintQueue, Process, PSAsyncMsg, Rope EXPORTS BansheeMarkerControl SHARES MarkerControlImpl = BEGIN ROPE: TYPE ~ Rope.ROPE; JobStatus: TYPE = {normal, paused, canceled, imagingError}; BansheeState: TYPE = RECORD [ jobStatus: JobStatus _ normal, job: BansheeEngine.JobHandle _ NIL, lastEngineStatus: BansheeStatus.Type _ okay, banner: PaperHandling.BannerMode _ oncePerJob, media: PaperTypes.Paper _ [knownSize: letter, otherSize: PaperTypes.nullDimensions]]; BansheeClientProcsHandle: TYPE = REF bansheeDl MarkerControl.ClientProcs; updateBansheeLog: CONDITION; engineStatusChange: CONDITION; jobStateChange: CONDITION; bansheeState: REF BansheeState _ NIL; bansheeClientProcs: BansheeClientProcsHandle _ NIL; lastActivityTimeStamp: BasicTime.GMT _ BasicTime.Now[]; --The time the last job completed marking. <<********************************>> <> <<*******************************>> Startup: PUBLIC INTERNAL PROCEDURE [priority: Process.Priority] RETURNS [MarkerControl.ClientProcsHandle] = TRUSTED BEGIN bansheeState _ NEW[BansheeState]; bansheeState.job _ NEW[BansheeEngine.Job _ [document: NIL]]; bansheeClientProcs _ NEW[ bansheeDl MarkerControl.ClientProcs _ [ start: MarkerControlInternal.Start, stop: MarkerControlInternal.Stop, stopped: MarkerControlInternal.Stopped, pause: MarkerControlInternal.Pause, resume: MarkerControlInternal.Resume, status: Status, waitStatusChange: WaitStatusChange, setPrintOrder: MarkerControlInternal.SetPrintOrder, modifyTraceLevel: MarkerControlInternal.ModifyTraceLevel, engineSpecific: bansheeDl[ setBanner: SetBansheeBanner] ]]; bansheeState.lastEngineStatus _ BansheeEngine.GetStatus[]; Process.Detach[FORK StatusChangeWatcher[]]; Process.Detach[FORK StatusWatcher[]]; Process.Detach[FORK BansheeLogUpdater[]]; Process.Detach[FORK MarkingControl[priority]]; BansheeCounter.ForceOut[]; -- to start the logging; fixes AR 12573 RETURN[bansheeClientProcs] END; -- Startup Status: PUBLIC PROCEDURE RETURNS [MarkerControl.MarkerStatus] = BEGIN bansheeState.media _ BansheeEngine.GetPaperSize[]; RETURN[ [ activity: root.state.activity, engineFault: root.state.engineProblem, engine: [bansheeDl[ banshee: bansheeState.lastEngineStatus, paper: bansheeState.media]]]]; END; --Status <<********************************>> <> <<********************************>> SetBansheeBanner: PROCEDURE [banner: PaperHandling.BannerMode] = BEGIN bansheeState.banner _ banner; END; --SetBanner WaitStatusChange: ENTRY PROCEDURE RETURNS [MarkerControl.MarkerStatus] = BEGIN ENABLE UNWIND => NULL; WAIT engineStatusChange; bansheeState.lastEngineStatus _ BansheeEngine.GetStatus[]; RETURN[Status[]]; END; --WaitStatusChange UpdateBansheeLog: ENTRY PROCEDURE = INLINE BEGIN ENABLE UNWIND => NULL; NOTIFY updateBansheeLog; END; --UpdateBansheeLog BansheeLogUpdater: ENTRY PROCEDURE = TRUSTED BEGIN ENABLE UNWIND => NULL; Process.SetTimeout[@updateBansheeLog, Process.SecondsToTicks[60 * 30 --secs/min-- ]]; Process.SetPriority[Process.priorityBackground]; DO -- forever WAIT updateBansheeLog; IF NOT root.state.idle THEN LOOP; IF root.state.trace = verbose THEN PSAsyncMsg.PutString["MarkerBansheeCounter.ForceOut"]; BansheeCounter.ForceOut[]; ENDLOOP; END; --BansheeLogUpdater GetLatestPaperSize: PROCEDURE = BEGIN Process.Pause [Process.MsecToTicks[500]]; --Must pause before getting paper size, or correct size will not have been posted yet. bansheeState.media _ BansheeEngine.GetPaperSize[]; END; --GetLatestPaperSize StatusChangeWatcher: ENTRY PROCEDURE = BEGIN -- updates the Banshee display if necessary ENABLE UNWIND => NULL; engineStatus: BansheeStatus.Type; DO -- forever engineStatus _ BansheeEngine.GetStatus[]; SELECT engineStatus FROM imageFault1, imageFault2, sequenceFault => BEGIN root.state.engineProblem _ TRUE; -- Stop everything when an imaging error is detected... root.state.stopStatus _ restart; root.control.stop _ TRUE; root.control.start _ root.control.pause _ root.control.resume _ root.control.pausing _ root.control.resuming _ root.control.resumeWhenAppropriate _ FALSE; bansheeState.jobStatus _ imagingError; BansheeEngine.SetPrintingState[completed]; END; okay => TRUSTED BEGIN Process.Detach [FORK GetLatestPaperSize[]]; --This proc is forked because it pauses before getting the current paper size and we don't want to hang up the StatusChangeWatcher with a pause or it might miss the next status change. IF root.state.activity = markingButInterruptable THEN root.state.activity _ marking; root.state.engineProblem _ FALSE; IF root.state.activity = paused OR root.control.pause THEN BEGIN root.control.resume _ TRUE; IF root.state.trace = verbose THEN PSAsyncMsg.PutString["Marker.Resume Internal"]; BROADCAST root.event; END; END; ENDCASE => BEGIN root.state.engineProblem _ TRUE; IF root.state.activity = marking THEN BEGIN root.state.activity _ markingButInterruptable; root.control.pause _ TRUE; IF root.state.trace = verbose THEN PSAsyncMsg.PutString["Marker.Pause Internal"]; BROADCAST root.event; END; END; bansheeState.lastEngineStatus _ engineStatus; WAIT engineStatusChange; ENDLOOP; END; --StatusChangeWatcher StatusWatcher: PROCEDURE = BEGIN -- Forked process status: BansheeStatus.Type; DO -- forever status _ BansheeEngine.WaitStatus[]; IF status # bansheeState.lastEngineStatus OR status IN [imageFault1..sequenceFault] <> THEN TRUSTED BEGIN Process.Detach[FORK NotifyStatusChange[status]]; -- avoid Monitor locks IF root.state.trace # none THEN PSAsyncMsg.PutString["Banshee Status Change"]; END; ENDLOOP; END; --StatusWatcher NotifyStatusChange: ENTRY PROCEDURE [status: BansheeStatus.Type] = BEGIN ENABLE UNWIND => NULL; bansheeState.lastEngineStatus _ status; BROADCAST engineStatusChange; END; --NotifyStatusChange MarkingControl: ENTRY PROCEDURE [priority: Process.Priority] = BEGIN ENABLE UNWIND => NULL; WaitJobState: PROCEDURE [ targetState: PrintingState.Type, targetEqual: BOOLEAN] RETURNS [pState: PrintingState.Type] = BEGIN -- FORKed to avoid MLs NotifyJobStateChange: ENTRY PROC = BEGIN NOTIFY jobStateChange; END; pState _ BansheeEngine.WaitPrintingState[targetState, targetEqual]; NotifyJobStateChange[]; END; --WaitJobState Process.SetPriority[priority]; DO --forever SELECT TRUE FROM root.control.tpQueueEntry AND root.state.idle => BEGIN -- over-rides root.state.stopped root.state.tpJob _ TRUE; IF NOT MarkDocument[tpDecomposed] THEN BEGIN root.control.tpQueueEntry _ FALSE; LOOP; END; END; root.control.stop => SELECT TRUE FROM root.state.stopped => NULL; NOT root.state.idle AND NOT bansheeState.jobStatus = canceled AND NOT bansheeState.jobStatus = imagingError => BEGIN root.control.start _ root.control.pause _ root.control.resume _ root.control.pausing _ root.control.resuming _ root.control.resumeWhenAppropriate _ FALSE; bansheeState.jobStatus _ canceled; BansheeEngine.SetPrintingState[completed]; END; root.state.idle => BEGIN root.state.stopped _ TRUE; NOTIFY root.stopped; END; ENDCASE; root.control.start => BEGIN root.control.start _ root.state.stopped _ root.control.pause _ root.control.resume _ root.control.pausing _ root.control.resuming _ root.control.resumeWhenAppropriate _ FALSE; -- so we don't keep looking here LOOP; -- make another pass END; root.control.pause => BEGIN IF root.state.activity IN [marking..markingButInterruptable] THEN TRUSTED BEGIN waitJobState: PROCESS RETURNS [PrintingState.Type]; engineState: PrintingState.Type; BansheeEngine.SetPrintingState[stopped]; waitJobState _ FORK WaitJobState[started, FALSE]; -- avoid MLs WAIT jobStateChange; engineState _ JOIN waitJobState; IF engineState = stopped THEN root.state.activity _ paused; root.control.resumeWhenAppropriate _ FALSE; IF root.state.trace = verbose THEN PSAsyncMsg.PutString["Marking Paused"]; END; NOTIFY root.paused; root.control.pause _ FALSE; END; root.control.resume OR root.control.resumeWhenAppropriate => BEGIN root.control.resumeWhenAppropriate _ FALSE; IF root.state.activity = paused AND BansheeEngine.GetPrintingState[] = stopped AND root.state.clientPause = 0 THEN BEGIN IF BansheeEngine.GetStatus[] = okay THEN TRUSTED BEGIN waitJobState: PROCESS RETURNS [PrintingState.Type]; engineState: PrintingState.Type; BansheeEngine.SetPrintingState[started]; waitJobState _ FORK WaitJobState[stopped, FALSE]; -- avoid MLs WAIT jobStateChange; engineState _ JOIN waitJobState; IF engineState = started THEN root.state.activity _ marking; IF root.state.trace = verbose THEN PSAsyncMsg.PutString["Marking Resumed"]; END ELSE BEGIN root.control.resumeWhenAppropriate _ TRUE; IF root.state.trace = verbose THEN PSAsyncMsg.PutString["Marker.ResumeWhenAppropriate"]; END; END; root.control.resume _ FALSE; END; NOT root.state.idle => NULL; -- so we don't start multiple markers root.control.jobQueueEntry => BEGIN IF NOT MarkDocument[decomposed] THEN BEGIN root.control.jobQueueEntry _ FALSE; LOOP; END; END; ENDCASE; WAIT root.event; ENDLOOP; END; --MarkingControl MarkDocument: INTERNAL PROCEDURE [fromQ: PrintQueue.QueueStage, qOH: PrintQueue.QueueObjectHandle _ PrintQueue.nilQueueObjectHandle] RETURNS [okay: BOOLEAN] = TRUSTED BEGIN root.state.qOH _ PrintQueue.Requeue[qOH: qOH, fromQueue: fromQ, toQueue: marking]; IF root.state.qOH = PrintQueue.nilQueueObjectHandle THEN RETURN[FALSE]; root.state.idle _ FALSE; root.state.activity _ marking; Process.Detach[FORK DoMarking]; IF root.state.trace # none THEN BEGIN PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR["Marking File \"%g\"; Copy Count: %g", IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.numberCopies]]]]; END; RETURN[TRUE]; END; -- MarkDocument DoMarking: PROCEDURE = BEGIN secondsToWait: LONG INTEGER _ 0; <> root.state.qOH.currentStatus _ marking; bansheeState.jobStatus _ normal; <> <> bansheeState.job.copyCount _ root.state.qOH.numberCopies; bansheeState.job.banner _ SELECT TRUE FROM root.state.tpJob => suppressed, root.state.qOH.bannerOnly => oncePerJob, ENDCASE => bansheeState.banner; BansheeEngine.SetJob[bansheeState.job]; IF root.state.waitBetweenJobs THEN BEGIN <<<>>> secondsToWait _ --last activity time plus wait time minus current time BasicTime.Period[ from: BasicTime.Update[lastActivityTimeStamp, root.state.betweenJobWaitTime], to: BasicTime.Now[]]; IF secondsToWait > 0 THEN BEGIN IF root.state.trace = verbose THEN BEGIN PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR["Wait %g seconds to allow spooling", IO.card[secondsToWait]]]]; END; Process.Pause[Process.SecondsToTicks[CARDINAL[secondsToWait]]]; --Wait a few seconds to allow spooling END; END; root.state.starting[]; root.state.startMarkDate _ BasicTime.Now[]; <> IF bansheeState.job.copyCount > 0 THEN BEGIN BansheeEngine.SetPrintingState[started]; [] _ BansheeEngine.WaitPrintingState[started, TRUE]; [] _ BansheeEngine.WaitPrintingState[completed, TRUE]; --returns when done END; root.state.finished[]; lastActivityTimeStamp _ BasicTime.Now[]; Queue[ SELECT bansheeState.jobStatus FROM normal => printed, imagingError => restart, ENDCASE => root.state.stopStatus]; MarkerControlInternal.SetActivity[available]; UpdateBansheeLog[]; END; -- DoMarking Queue: ENTRY PROCEDURE [status: PrintQueue.ObjectStatus] = BEGIN ENABLE UNWIND => NULL; nsDone: ROPE _ "Done Marking \"%g\"; seconds = %g"; nsFail: ROPE _ "Mark Failure on \"%g\"; seconds = %g"; p: CARD _ BasicTime.Period[from: lastActivityTimeStamp, to: root.state.startMarkDate]; IF p >= 0 THEN root.state.qOH.markTime _ p; root.state.qOH.currentStatus _ status; SELECT TRUE FROM status = printed OR root.state.tpJob --any tp failure-- => BEGIN IF root.state.trace # none THEN PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR[nsDone, IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.markTime]]]]; [] _ PrintQueue.Requeue[ qOH: root.state.qOH, fromQueue: marking, toQueue: marked]; END; status = restart => BEGIN -- requeue document <<<>>> IF root.state.trace # none THEN PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR[nsDone, IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.markTime]]]]; IF root.state.qOH.printObjectHandle # NIL THEN BEGIN <> <> root.state.qOH.printObjectHandle _ NIL; END; [] _ PrintQueue.Requeue[qOH: root.state.qOH, fromQueue: marking, toQueue: spooledNormal, position: front]; IF bansheeState.jobStatus = imagingError THEN TRUSTED BEGIN Process.Detach[FORK root.state.engineFailure[]]; END; END; status = canceledInMarker => BEGIN IF root.state.trace # none THEN PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR[nsDone, IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.markTime]]]]; [] _ PrintQueue.Requeue[qOH: root.state.qOH, fromQueue: marking, toQueue: aborted]; IF root.state.canceledWhileMarking # NIL THEN root.state.canceledWhileMarking[root.state.qOH.fileName, status]; END; ENDCASE => BEGIN IF root.state.trace # none THEN PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR[nsFail, IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.markTime]]]]; [] _ PrintQueue.Requeue[qOH: root.state.qOH, fromQueue: marking, toQueue: errors]; END; bansheeState.job.lastPage _ LAST[CARDINAL]; -- was modified by BansheeEngine?? root.state.tpJob _ FALSE; root.control.jobQueueEntry _ NOT PrintQueue.Empty[decomposed]; root.control.tpQueueEntry _ NOT PrintQueue.Empty[tpDecomposed]; BROADCAST root.event; -- in case there's something to do END; --Queue END. --BansheeMarkerControlImpl LOG when - who - what 19-Sep-84 13:52:32 - Strickberger - Created based on RavenMarkerControlImpl of 30-Aug-84 13:02:13. 8-Nov-84 16:52:08 - Jacks - Updated to second round of 9.0 interface changes; changed Stop parm from queue to status. 16-Jan-85 16:15:17 - Jacks - Put pause in "okay" arm of select stmt in StatusChangeWatcher to give time for paper size to be updated. 4-Feb-85 13:36:55 - Jacks - Moved SetActivity[available] after Queue[] at end of DoMarking. 17-Jun-85 16:08:32 - Jacks - Added copyright notice; updated to PS Euclid interfaces. 6-Aug-85 9:06:14 - Jacks - Updated to 10.0 DecomposerControl.FreeDecomposeObject. 23-Sep-85 15:22:18 - Jacks - String.AppendLongDecimal sCopies in MarkDocument to avoid Bounds Fault; only pause between jobs if client requests it. 4-Oct-85 9:33:49 - Jacks - Set printObjectHandle to NIL after calling DecomposerControl.FreeDecomposeObject. 21-Oct-85 17:12:44 - Jacks - Converted to new banshee paper def. 1-Nov-85 11:09:42 - Jacks - Check for copyCount=0 in DoMarking. 23-Apr-86 16:34:54 - Jacks - Added code for recognizing image faults in StatusChangeWatcher and dealing correctly with markFailure in Queue; requeue restart docs to FRONT of spooled queue.