<> <> <> <> <> DIRECTORY BansheeCodes USING [PrinterCommand, PrinterStatus], BansheeControl USING [EngineDiagnostic, EngineDisplayDigit, EngineEvent, EnginePaper, EngineStatus, LogItem, PlateStatus], Basics USING [LongMult], BasicTime USING [Pulses, MicrosecondsToPulses, GetClockPulses], Interrupt USING [Initialize, Object, Wait], LSEPFace USING [AdvanceBand, AllocateBands, BandBufferCount, BandFull, BandOverrun, GetStatus, Index, InitializeCleanUp, LastBand, PutCommand, SetInterruptMasks, SetPageOffsets, SetScanLineLength, StartImage, ResetBands], PrincOps USING [PageCount, wordsPerPage], PrincOpsUtils USING [LongCopy], Process USING [Detach, MsecToTicks, Pause, priorityFaultHandlers, priorityRealTime, SetPriority, SecondsToTicks], Queue USING [Initialize, Object, Pop, Push], SharedQueue USING [GetCurrentHead, Initialize, Object, Pop, Push], Synchronizer USING [Broadcast, Initialize, Notify, Object, Wait], VM USING [Allocate, AddressForPageNumber, Interval, Pin]; BansheeControlImpl: PROGRAM IMPORTS Basics, BasicTime, Interrupt, LSEPFace, PrincOpsUtils, Process, Queue, SharedQueue, Synchronizer, VM EXPORTS BansheeControl = BEGIN <> Band: TYPE = ARRAY [0 .. bandBufferSize * PrincOps.wordsPerPage) OF WORD; EventContext: PUBLIC TYPE = CARDINAL; ScanLine: TYPE = [0..16); -- scan line index into a band <> bandBufferSize: PrincOps.PageCount = 16; -- From BandBLT wordsPerScanLine: CARDINAL = 160; -- 8.5" * 300BitsPer" / 16BitsPerWord pagesPerBand: CARDINAL = 10; -- 160WordsPerScanLine * 16ScanLinesPerBand / 256WordsPerPage vmMaxBandRequest: CARDINAL = 22; -- max bands to swap - avoids Pilot > 256 page swap bug bandBufferPadding: PrincOps.PageCount = 1; -- to allow for overwrite when copying due to offset of short scan lines commandSent, engineEvent, newStatus, newDiagnosticStatus, pageSync, revisionReceived, statusReceived, imagingComplete: Synchronizer.Object; controlInt, imageInt, statusInt: Interrupt.Object; commandQ, logQ, turnaroundQ: Queue.Object; eventQ: SharedQueue.Object; engineState: {okay, error} _ error; transferStatus: {ready, notReady} _ notReady; statusInternal: BansheeControl.EngineStatus _ communicationFault; offlineMode: BOOLEAN _ FALSE; lastCommand: BansheeCodes.PrinterCommand; paperSizeInternal: BansheeControl.EnginePaper _ paperLetter; revisionInternal: CARDINAL _ 0; engineDiagnosticInternal: BansheeControl.EngineDiagnostic; maxBands: CARDINAL _ 207; -- max bands on this page, init to 11" abortImaging: BOOLEAN _ FALSE; flushPrinter: BOOLEAN _ FALSE; lastBand: BOOLEAN; imagingActive: BOOLEAN _ FALSE; serverLoopbackMode: BOOLEAN _ FALSE; -- server Loop Back diagnostic test printerLoopbackMode: BOOLEAN _ FALSE; -- printer Loop Back diagnostic test printerLoopbackModeOn: CARDINAL _ 0; -- counter for WatchErrorStatus to avoid polling conflict statusQuery: BOOLEAN _ FALSE; -- did we request this status? revisionQuery: BOOLEAN _ FALSE; -- did we request firware revision level? pagesInProcess: CARDINAL _ 0; -- number of pages in the paper path pageSyncPulses: BasicTime.Pulses; -- when the page 0 pageSync occurred pageDeliveryDelayPulses: BasicTime.Pulses = BasicTime.MicrosecondsToPulses[6500000]; band, bandFirst, bandLast: LSEPFace.Index; bandBufferCount: LSEPFace.BandBufferCount; bandLowCore: VM.Interval; printUnlimitedMode: BOOLEAN _ FALSE; -- full page buffering mode <> pageBufferInterval: VM.Interval; -- full page buffer interval pageBufferActivateCount: CARDINAL _ 4; -- bands to activate ahead when BandBLTing page buffer pageBufferIndex: CARDINAL; -- index to current band in page buffer pageBufferIndexLast: CARDINAL; -- last meaningful band in page buffer pageBufferBandBuffer: LONG POINTER; -- band buffer virtual address EventLogIndex: TYPE = [0..32); eventLogIndex: EventLogIndex _ 0; eventLog: ARRAY EventLogIndex OF BansheeControl.EngineEvent _ ALL[timeout]; <> <<>> unlimitedAvailable: PUBLIC BOOLEAN _ FALSE; <> <<>> Initialize: PUBLIC SAFE PROCEDURE [bufferSize: PrincOps.PageCount, enableUnlimited: BOOLEAN] = TRUSTED BEGIN controlMask: WORD = Interrupt.Initialize[ interrupt: @controlInt, enableAbort: TRUE, enableTimeout: FALSE]; imageMask: WORD = Interrupt.Initialize[ interrupt: @imageInt, enableAbort: TRUE, enableTimeout: FALSE]; statusMask: WORD = Interrupt.Initialize[ interrupt: @statusInt, enableAbort: TRUE, enableTimeout: FALSE]; Process.Detach[FORK LSEPFace.InitializeCleanUp]; LSEPFace.SetInterruptMasks[control: controlMask, status: statusMask, data: imageMask]; Queue.Initialize[queue: @commandQ]; Queue.Initialize[queue: @logQ]; Queue.Initialize[queue: @turnaroundQ]; SharedQueue.Initialize[queue: @eventQ, enableAbort: TRUE, enableTimeout: TRUE, lapse: 20000]; -- event timeout 20 seconds Synchronizer.Initialize[synchronizer: @commandSent, enableAbort: TRUE, enableTimeout: FALSE]; Synchronizer.Initialize[synchronizer: @engineEvent, enableAbort: TRUE, enableTimeout: TRUE, lapse: 22000]; Synchronizer.Initialize[synchronizer: @newStatus, enableAbort: TRUE, enableTimeout: FALSE]; Synchronizer.Initialize[synchronizer: @newDiagnosticStatus, enableAbort: TRUE, enableTimeout: FALSE]; Synchronizer.Initialize[synchronizer: @pageSync, enableAbort: TRUE, enableTimeout: FALSE]; Synchronizer.Initialize[synchronizer: @revisionReceived, enableAbort: TRUE, enableTimeout: TRUE, lapse: 1000]; Synchronizer.Initialize[synchronizer: @statusReceived, enableAbort: TRUE, enableTimeout: TRUE, lapse: 1000]; Synchronizer.Initialize[synchronizer: @imagingComplete, enableAbort: TRUE, enableTimeout: TRUE, lapse: 12000]; LSEPFace.SetPageOffsets[wordsFast: 4, linesSlow: 2]; -- absolute minimum offsets <> bandBufferCount _ bufferSize / bandBufferSize; bandLowCore _ VM.Allocate[bufferSize + bandBufferPadding]; LSEPFace.AllocateBands[bandVM: bandLowCore, nBands: bandBufferCount, sizeEachBand: bandBufferSize]; LSEPFace.SetScanLineLength[activeWordsEachScanline: 160]; -- 8.5" wide FOR i: INT _ 0, i+400 UNTIL i >= pageBufferInterval.count DO -- only pin about 100K each time VM.Pin[[page: pageBufferInterval.page+i, count: MIN[pageBufferInterval.count-i, 400]]]; Process.Pause[Process.MsecToTicks[500]]; -- wait a half second for Laundry process ENDLOOP; Process.Detach[FORK HandleCommand]; -- priority = 6 Process.Detach[FORK WatchCommandStatus]; -- priority = 6 Process.Detach[FORK WatchErrorStatus]; -- priority = 5 Process.Detach[FORK HandleImage]; -- priority = 6 Process.Detach[FORK HandleStatus]; -- priority = 6 Process.Detach[FORK WatchImaging]; -- priority = 6 SendEngineCommand[solicitStatus]; SendEngineCommand[solicitPaperSize]; END; -- Initialize BandBLTTransferReady: PUBLIC SAFE PROCEDURE = TRUSTED BEGIN END; -- BandBLTTransferReady <> <> PageTransferSet: PUBLIC SAFE PROCEDURE[pageNumber: CARDINAL] = TRUSTED BEGIN <<<< -- Forceout/Deactivate all of VM >> Needs to build bitmap!!!>> pageBufferIndex _ 0; WHILE pageBufferIndex <= pageBufferIndexLast DO loopBandCount: CARDINAL _ MIN[ pageBufferIndexLast - pageBufferIndex + 1, vmMaxBandRequest]; <> <> <> <> <> pageBufferIndex _ pageBufferIndex + loopBandCount; ENDLOOP; <> [firstBand: band, firstBandAddress: pageBufferBandBuffer] _ LSEPFace.ResetBands[]; bandFirst _ band; pageBufferIndex _ 0; lastBand _ FALSE; THROUGH [0..bandBufferCount) UNTIL lastBand DO BandCopyInternal; ENDLOOP; printUnlimitedMode _ TRUE; transferStatus _ ready; BroadcastEngineEvent[transferReady]; END; -- PageTransferSet TransferRelease: PUBLIC SAFE PROCEDURE = TRUSTED BEGIN --Do Nothing IF imagingActive THEN abortImaging _ TRUE; transferStatus _ notReady; END; -- TransferRelease SendEngineCommand: PUBLIC SAFE PROCEDURE [cmd: BansheeCodes.PrinterCommand] = TRUSTED BEGIN Queue.Push[@commandQ, cmd]; END; -- SendEngineCommand Display: PUBLIC SAFE PROCEDURE [digitLS, digitMS: BansheeControl.EngineDisplayDigit] = TRUSTED BEGIN SendEngineCommand[LOOPHOLE[digitLS]]; SendEngineCommand[LOOPHOLE[ORD[digitMS] + 10H]]; END; -- Display GetEngineStatus: PUBLIC SAFE PROCEDURE RETURNS [BansheeControl.EngineStatus] = TRUSTED BEGIN RETURN[IF (statusInternal = okay OR statusInternal = noToner) AND flushPrinter THEN okayFlushRequired ELSE statusInternal]; END; -- GetEngineStatus GetEnginePaper: PUBLIC SAFE PROCEDURE RETURNS [BansheeControl.EnginePaper] = TRUSTED BEGIN RETURN[paperSizeInternal]; END; -- GetEnginePaper GetEngineFirmwareRevision: PUBLIC SAFE PROCEDURE RETURNS [CARDINAL] = TRUSTED BEGIN revisionInternal _ 0; SendEngineCommand[solicitRevisionLevel]; [] _ Synchronizer.Wait[@revisionReceived]; RETURN[revisionInternal]; END; -- GetEngineFirmwareRevision WaitEngineEvent: PUBLIC SAFE PROCEDURE [eventContext: REF EventContext] RETURNS [event: BansheeControl.EngineEvent] = TRUSTED BEGIN event _ LOOPHOLE[SharedQueue.Pop[@eventQ, eventContext]]; IF event = LOOPHOLE[LAST[CARDINAL]] THEN event _ timeout; END; -- WaitEngineEvent SetToCurrentEventContext: PUBLIC SAFE PROCEDURE [eventContext: REF EventContext] = TRUSTED BEGIN SharedQueue.GetCurrentHead[@eventQ, eventContext] END; WaitEngineStatus: PUBLIC SAFE PROCEDURE RETURNS [BansheeControl.EngineStatus] = TRUSTED {[] _ Synchronizer.Wait[@newStatus]; RETURN[GetEngineStatus[]]}; -- WaitEngineStatus WaitLogItem: PUBLIC SAFE PROCEDURE RETURNS [BansheeControl.LogItem] = TRUSTED {RETURN[Queue.Pop[@logQ]]}; RunTurnaroundTest: PUBLIC SAFE PROCEDURE RETURNS [ok: BOOLEAN] = TRUSTED BEGIN codeOut, codeIn: CARDINAL [0..177B]; ok _ TRUE; serverLoopbackMode _ TRUE; FOR codeOut IN [1..177B] DO -- send each code and check recieve (avoid Head problems with 0) SendEngineCommand[LOOPHOLE[codeOut]]; codeIn _ Queue.Pop[queue: @turnaroundQ]; IF codeIn # codeOut THEN BEGIN ok _ FALSE; EXIT; END; ENDLOOP; serverLoopbackMode _ FALSE; SendEngineCommand[solicitStatus]; -- make sure command/status polling continues Process.Pause[Process.MsecToTicks[200]]; -- wait for command to be sent END; WaitEngineDiagnostic: PUBLIC SAFE PROCEDURE RETURNS [BansheeControl.EngineDiagnostic] = TRUSTED BEGIN [] _ Synchronizer.Wait[@newDiagnosticStatus]; RETURN[engineDiagnosticInternal]; END; -- WaitEngineDiagnostic <> <> BandBLTInternal: PROCEDURE = INLINE BEGIN <> <> <> <> <<[bandBLTTableInternal.writeLO, bandBLTTableInternal.readLO] _ Swap[>> <> <> <> <> <> <<[nextBand: band, nextBandAddress: bandBLTTableInternal.bandbuf] _>> <> END; -- BandBLTInternal BandCopyInternal: PROCEDURE = TRUSTED INLINE BEGIN <> FOR scanIndex: ScanLine IN [FIRST[ScanLine]..LAST[ScanLine]] DO PrincOpsUtils.LongCopy[ from: PageBufferAddress[pageBufferIndex, scanIndex], nwords: wordsPerScanLine, to: LOOPHOLE[LOOPHOLE[pageBufferBandBuffer, LONG CARDINAL] + scanIndex * 256]]; ENDLOOP; IF abortImaging OR (pageBufferIndex _ pageBufferIndex + 1) > pageBufferIndexLast THEN {lastBand _ TRUE; bandLast _ band}; <> [nextBand: band, nextBandAddress: pageBufferBandBuffer] _ LSEPFace.AdvanceBand[currentBand: band]; END; -- BandCopyInternal PageBufferAddress: PROCEDURE [bandIndex: CARDINAL, scanLine: ScanLine] RETURNS [LONG POINTER] = INLINE BEGIN RETURN[LOOPHOLE[VM.AddressForPageNumber[pageBufferInterval.page] + Basics.LongMult[bandIndex, pagesPerBand * 256] + LONG[scanLine * wordsPerScanLine]]]; END; -- PageBufferAddress BroadcastEngineEvent: PROCEDURE [event: BansheeControl.EngineEvent] = TRUSTED BEGIN IF event IN [feedError..hardError] THEN engineState _ error; -- set to okay by HandleStatus SharedQueue.Push[@eventQ, LOOPHOLE[event]]; eventLog[eventLogIndex] _ event; eventLogIndex _ (eventLogIndex + 1) MOD LAST[EventLogIndex]; END; -- BroadcastEngineEvent SetEngineStatus: PROCEDURE [status: BansheeControl.EngineStatus] = TRUSTED BEGIN IF statusInternal # status OR status = okay THEN {statusInternal _ status; Synchronizer.Broadcast[@newStatus]}; END; -- SetEngineStatus <> HandleCommand: PROCEDURE = TRUSTED BEGIN <> Process.SetPriority[Process.priorityRealTime]; DO -- forever lastCommand _ Queue.Pop[@commandQ]; -- waits till queue is non-empty SELECT TRUE FROM serverLoopbackMode => Synchronizer.Notify[@commandSent]; printerLoopbackMode => IF ORD[lastCommand] = 177B THEN printerLoopbackMode _ FALSE ELSE Synchronizer.Notify[@commandSent]; ENDCASE => BEGIN SELECT lastCommand FROM feed, solicitStatus, solicitPaperSize, solicitRevisionLevel => Synchronizer.Notify[@commandSent]; ENDCASE => NULL; SELECT lastCommand FROM solicitStatus => statusQuery _ TRUE; ENDCASE => NULL; Queue.Push[@logQ, BansheeControl.LogItem[command[lastCommand]]]; END; LSEPFace.PutCommand[ORD[lastCommand]]; -- send the command Interrupt.Wait[@controlInt]; -- wait for IOP to send IF NOT (serverLoopbackMode OR printerLoopbackMode) THEN Process.Pause[Process.MsecToTicks[20]]; -- allow IOT time to think ENDLOOP; END; -- HandleCommand HandleImage: PROCEDURE = BEGIN bandOverrun: BOOLEAN; -- did a band overrun occur on this plate bandsCount: CARDINAL; -- number of bands processed WaitBandEmpty: PROCEDURE [thisBand: LSEPFace.Index] = INLINE BEGIN WHILE LSEPFace.BandFull[thisBand] DO Interrupt.Wait[@imageInt]; ENDLOOP; END; Process.SetPriority[Process.priorityFaultHandlers]; DO -- forever <> [] _ Synchronizer.Wait[@pageSync]; IF transferStatus = notReady THEN BEGIN -- page sync missed Process.Pause[Process.MsecToTicks[100]]; -- insure that this event is not missed Synchronizer.Broadcast[@imagingComplete]; -- for WatchImaging BroadcastEngineEvent[pageSyncMiss]; Queue.Push[@logQ, BansheeControl.LogItem[plateStatus[pageSyncMiss]]]; LOOP; END; bandOverrun _ FALSE; imagingActive _ TRUE; LSEPFace.StartImage[bandFirst]; FOR bandsCount _ 0, bandsCount + 1 UNTIL lastBand DO WaitBandEmpty[band]; IF abortImaging OR bandsCount > maxBands THEN BEGIN bandLast _ band; EXIT; END; IF printUnlimitedMode THEN BandCopyInternal ELSE BandBLTInternal; IF LSEPFace.BandOverrun[] THEN BEGIN -- imaging got ahead of filling LSEPFace.StartImage[LOOPHOLE[0]]; -- reset Head overrun flag bandOverrun _ TRUE; -- to use later bandsCount _ bandsCount + 2; -- limit page to 2 less bands END; ENDLOOP; LSEPFace.LastBand[bandLast]; -- indicate that last band has been filled WaitBandEmpty[bandLast]; -- wait till last band has been imaged IF statusInternal = imageFault1 OR flushPrinter THEN BEGIN -- the image fault is cleared or the flush completed flushPrinter _ FALSE; -- flush (if) is done, back to normal marking SetEngineStatus[okay]; -- tell upper levels status has changed END; imagingActive _ abortImaging _ FALSE; Synchronizer.Broadcast[@imagingComplete]; -- for WatchImaging TransferRelease[]; IF bandOverrun THEN BEGIN <> BroadcastEngineEvent[imagedOverrun]; Queue.Push[@logQ, BansheeControl.LogItem[plateStatus[bandOverrun]]]; END ELSE BroadcastEngineEvent[imaged]; ENDLOOP; END; -- HandleImage HandleStatus: PROCEDURE = TRUSTED BEGIN sts: BansheeCodes.PrinterStatus; lastPolledStatus: BansheeCodes.PrinterStatus _ readyToFeed; revisionFollows: BOOLEAN _ FALSE; Process.SetPriority[Process.priorityRealTime]; DO -- forever Interrupt.Wait[@statusInt]; -- wait for status from IOT sts _ LOOPHOLE[LSEPFace.GetStatus[]]; -- get received status IF serverLoopbackMode OR printerLoopbackMode OR revisionFollows THEN BEGIN SELECT TRUE FROM serverLoopbackMode => Queue.Push[@turnaroundQ, sts]; printerLoopbackMode => SendEngineCommand[LOOPHOLE[sts]]; revisionFollows => BEGIN revisionFollows _ FALSE; revisionInternal _ ORD[sts]; Synchronizer.Broadcast[@revisionReceived]; END; ENDCASE => ERROR; Synchronizer.Notify[@statusReceived]; -- something was received LOOP; -- don't process like real status END; SELECT sts FROM noStatus, statusError, statusOverRun => -- read status and try again SendEngineCommand[solicitStatus]; LOOPHOLE[BansheeCodes.PrinterCommand[solicitStatus]], LOOPHOLE[BansheeCodes.PrinterCommand[displayP4]] => NULL; -- loopback? ENDCASE => Synchronizer.Notify[@statusReceived]; -- legit status SELECT sts FROM pageSync => BEGIN -- handle this status first for better performance Synchronizer.Broadcast[@pageSync]; BroadcastEngineEvent[feeding]; -- also used as the feeding status IF pagesInProcess = 0 THEN pageSyncPulses _ BasicTime.GetClockPulses[]; pagesInProcess _ pagesInProcess + 1; END; revisionLevelPrefix => -- next status is IOT revision level revisionFollows _ TRUE; feedRejected => BEGIN -- send solicitStatus to find out why BroadcastEngineEvent[feedError]; SendEngineCommand[solicitStatus]; END; readyToFeed => BEGIN SELECT TRUE FROM engineState = error => BEGIN -- state was error, now okay, get paper size IF imagingActive THEN BEGIN -- flush required to finish imaging abortImaging _ TRUE; flushPrinter _ TRUE; END; pagesInProcess _ 0; SendEngineCommand[solicitPaperSize]; BroadcastEngineEvent[readyToFeed]; END; statusQuery => NULL; -- not an event if we asked for it ENDCASE => BroadcastEngineEvent[readyToFeed]; engineState _ okay; END; pageDelivered => IF BasicTime.GetClockPulses[] > pageSyncPulses + pageDeliveryDelayPulses THEN BEGIN pagesInProcess _ pagesInProcess - 1; BroadcastEngineEvent[pageDelivery]; END; preregistrationJam, noPaper, feedTrayNotEngaged, outputTrayFull, noToner, copyModeOn => BroadcastEngineEvent[feedError]; callForService, fuserJam, noExit, clamShellOpen => BroadcastEngineEvent[hardError]; IN [paperLetter..paperEnvelopeRX] => BEGIN paperSizeInternal _ sts; maxBands _ SELECT sts FROM -- set limit on number of bands paperLetter => 207, -- 11" long paperA4 => 220, -- 297mm long paper215X330 => 244, -- 330mm long paperLegal => 263, -- 14" long paperEnvelope10 => 188, -- 10" long paperEnvelopeRX => 220, -- ? ENDCASE => ERROR; SELECT sts FROM paperEnvelope10, paperEnvelopeRX => BEGIN -- envelopes print on outside 4.5" only LSEPFace.SetScanLineLength[activeWordsEachScanline: 85]; -- 4.5" wide LSEPFace.SetPageOffsets[wordsFast: 79, linesSlow: 2]; -- indent 4" END; ENDCASE => BEGIN -- normal papers print full width LSEPFace.SetScanLineLength[activeWordsEachScanline: 160]; -- 8.5" wide LSEPFace.SetPageOffsets[wordsFast: 4, linesSlow: 2]; -- absolute minimum offsets END; END; IN [test36..testStop] => BEGIN offlineMode _ FALSE; engineDiagnosticInternal _ LOOPHOLE[sts]; Synchronizer.Broadcast[@newDiagnosticStatus]; SELECT sts FROM IN [test42..test44] => BEGIN SetEngineStatus[diagnosticOkay]; BroadcastEngineEvent[readyToFeed]; END; test47Loopback => BEGIN printerLoopbackMode _ TRUE; printerLoopbackModeOn _ 3; -- avoid status polling conflicts with WatchErrorStatus SendEngineCommand[LOOPHOLE[sts]]; SetEngineStatus[diagnosticNotReady]; BroadcastEngineEvent[hardError]; END; testStop => BEGIN SetEngineStatus[diagnosticNotReady]; BroadcastEngineEvent[softError]; END; ENDCASE => BEGIN SetEngineStatus[diagnosticNotReady]; BroadcastEngineEvent[hardError]; END; END; diagnosticMode => BEGIN offlineMode _ FALSE; SetEngineStatus[diagnosticNotReady]; BroadcastEngineEvent[hardError]; END; keyOffLine => BEGIN offlineMode _ NOT offlineMode; Synchronizer.Broadcast[@newStatus]; IF offlineMode THEN BEGIN SendEngineCommand[offLineOn]; BroadcastEngineEvent[feedError]; END ELSE BEGIN SendEngineCommand[offLineOff]; IF statusInternal = okay THEN BroadcastEngineEvent[readyToFeed]; END; END; ENDCASE => NULL; -- ignore others IF statusQuery THEN BEGIN statusQuery _ FALSE; IF sts # lastPolledStatus THEN Queue.Push[@logQ, BansheeControl.LogItem[printerStatus[sts]]]; lastPolledStatus _ sts; -- save the polled status END ELSE Queue.Push[@logQ, BansheeControl.LogItem[printerStatus[sts]]]; SELECT sts FROM preregistrationJam, noPaper, callForService, fuserJam, noExit, clamShellOpen, readyToFeed, feedTrayNotEngaged, outputTrayFull, noToner, copyModeOn => BEGIN IF statusInternal = communicationFault THEN BEGIN SendEngineCommand[offLineOff]; SendEngineCommand[lastPageOff]; -- could have been set by noise Display[blank, blank]; -- clear any display END; IF statusInternal # diagnosticNotReady AND statusInternal # diagnosticOkay THEN SetEngineStatus[SELECT sts FROM preregistrationJam => preregistrationJam, noPaper => noPaper, callForService => callForService, fuserJam => fuserJam, noExit => noExit, clamShellOpen => clamShellOpen, readyToFeed => okay, feedTrayNotEngaged => feedTrayNotEngaged, outputTrayFull => outputTrayFull, noToner => noToner, copyModeOn => copyModeOn, ENDCASE => ERROR]; END; ENDCASE => NULL; ENDLOOP; END; -- HandleStatus WatchCommandStatus: PROCEDURE = TRUSTED BEGIN commandStatusTimeout: BOOLEAN; Process.SetPriority[Process.priorityRealTime]; DO -- forever [] _ Synchronizer.Wait[@commandSent]; -- notification by HandleCommand IF lastCommand = feed AND NOT (serverLoopbackMode OR printerLoopbackMode) THEN THROUGH [1..16] WHILE commandStatusTimeout _ Synchronizer.Wait[ @statusReceived] DO ENDLOOP ELSE commandStatusTimeout _ Synchronizer.Wait[@statusReceived]; IF commandStatusTimeout THEN SELECT TRUE FROM serverLoopbackMode => Queue.Push[@turnaroundQ, 200B]; -- make turnaround test fail printerLoopbackMode => BEGIN printerLoopbackMode _ FALSE; SendEngineCommand[solicitStatus]; END; ENDCASE => BEGIN SendEngineCommand[solicitStatus]; SendEngineCommand[displayP4]; IF statusInternal # communicationFault THEN BEGIN offlineMode _ FALSE; SetEngineStatus[communicationFault]; BroadcastEngineEvent[hardError]; engineDiagnosticInternal _ endDiagnosticMode; Synchronizer.Broadcast[@newDiagnosticStatus]; Queue.Push[@logQ, BansheeControl.LogItem[softwareStatus[communicationFault]]]; END; END; ENDLOOP; END; -- WatchCommandStatus WatchErrorStatus: PROCEDURE = BEGIN Process.SetPriority[Process.priorityFaultHandlers]; DO -- forever IF statusInternal IN [noPaper..diagnosticNotReady] THEN BEGIN SELECT TRUE FROM serverLoopbackMode => NULL; printerLoopbackModeOn > 0 => printerLoopbackModeOn _ printerLoopbackModeOn - 1; -- delay to avoid conflicts ENDCASE => SendEngineCommand[solicitStatus]; Process.Pause[Process.SecondsToTicks[2]]; END ELSE [] _ Synchronizer.Wait[@newStatus]; ENDLOOP; END; -- WatchErrorStatus WatchImaging: PROCEDURE = TRUSTED BEGIN Process.SetPriority[Process.priorityRealTime]; DO -- forever [] _ Synchronizer.Wait[@pageSync]; <> IF Synchronizer.Wait[@imagingComplete] -- notification by HandleImage AND imagingActive THEN BEGIN abortImaging _ TRUE; -- abort BandBLT or BandCopy loop IF engineState = okay THEN BEGIN -- image fault only if no engine error IF statusInternal # diagnosticNotReady AND statusInternal # diagnosticOkay THEN SetEngineStatus[imageFault1]; BroadcastEngineEvent[hardError]; Queue.Push[@logQ, BansheeControl.LogItem[softwareStatus[imageFault1]]]; END; END; ENDLOOP; -- forever END; -- WatchImaging END. LOG When / Who / What. 11-Dec-84 2:09:39 / Strickberger / Created. 27-Jan-85 16:51:14 / Strickberger / Fix diagnostic status handling. 19-Feb-85 17:30:40 / Strickberger / Add psuedo offline mode. 27-Feb-85 17:24:46 / Strickberger / Add printer loopback mode implementation, increase feed command response timeout. 1-Apr-85 23:25:13 / Strickberger / Change flush logic to incorporate EngineStatus of okayFlushRequired, and not feed when status _ okay - part of ImageFault fix (AR13951). 20-May-85 10:50:05 / Strickberger / Modify HandleImage to count bands as imaged and limit by 2 if band overrun occurs, avoids being imaging when Banshee disables clock after many band overruns (AR14287). Fix abortImage handling in HandleImage loop. Always Broadcast newStatus in SetEngineStatus if new status is okay, unsticks image fault status at engine level (AR13794). Added eventLog for easier debugging. 23-May-85 23:38:59 / Strickberger / Added printerLoopbackModeOn counter to delay extra seconds cycle in WatchErrorStatus if previously in loopback mode. Prevents conflict when 2 sec expires exactly between loopback runs. Check statusInternal # diagnostic before calling SetEngineStatus[imageFault] (avoids half-ass exit from repair mode). 26-Jun-85 23:34:53 / Strickberger / Fix order of BroadcastEngineEvent calls in HandleStatus if image fault. Don't notify statusRecieived if bad status. Fix priority usage. 12-Aug-85 23:44:42 / Strickberger / Add unlimited printing. Update for Pilot 12. Don't notify statusRecieived if looped back solicitStatus. FixArrows. 19-Sep-85 19:07:50 / Strickberger / Added enableUnlimited parameter to Initialize. Properly handle Volume.InsufficientSpace and Space.InsufficientSpace in Initialize. Broadcast softError instead of hardError on daignostic testStop status. 2-Oct-85 13:00:31 / Strickberger / Turn off Last Page after communication fault. 18-Oct-85 14:39:27 / Strickberger / Added code to call LSEPFace.SetScanLineLength and LSEPFace.SetPageOffsets depending on paper size for envelope printing. 24-Feb-86 11:52:20 / Strickberger / Don't notify statusRecieived if looped back displayP4. Don't exit imaging loop until bandsCount > maxBands. 20-Apr-86 22:12:24 / Strickberger / Pause before sending pageSyncMiss event in HandleImage, to not overwrite feeding event which is coupled to page sysnc. 5-May-86 0:23:58 / Strickberger / Detect imageFault with WatchImaging procedure instead of checking imagingActive at pageEelivered and pageSync, to avoid copy while printing problems (AR4127). Clear imageFault status and flushPrinter in HandleImage, not in HandleStatus (pageAtOutputTray); don't care about flushPrinter or transferStatus or BandOverrun in WatchImaging; pause before broadcasting imagingComplete and pageSyncMiss event in HandleImage to avoid missed notifys. (from Raven AR3999). 14-May-86 19:50:27 / Prochaska / Modified WaitEngineEvent[], BroadcastEngineEvent[] to use SharedQueue; Added SetToCurrentEventContext[]. 21-May-86 13:58:47 / Strickberger / Added logic to ignore pageDelivered when following previous pageSync by correct time, fixes printing while copying (AR4126).