BansheeControlImpl.mesa
Copyright (C) Xerox Corporation 1985, 1986. All rights reserved.
last edited by prochaska 14-May-86 14:00:10
Ruseli Binsol: October 9, 1986 2:22:47 pm PDT
Tim Diebert: December 2, 1986 3:12:02 pm PST
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
TYPEs:
Band: TYPE = ARRAY [0 .. bandBufferSize * PrincOps.wordsPerPage) OF WORD;
EventContext: PUBLIC TYPE = CARDINAL;
ScanLine: TYPE = [0..16); -- scan line index into a band
Constants:
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: BOOLEANFALSE;
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: BOOLEANFALSE;
flushPrinter: BOOLEANFALSE;
lastBand: BOOLEAN;
imagingActive: BOOLEANFALSE;
serverLoopbackMode: BOOLEANFALSE; -- server Loop Back diagnostic test
printerLoopbackMode: BOOLEANFALSE; -- printer Loop Back diagnostic test
printerLoopbackModeOn: CARDINAL ← 0; -- counter for WatchErrorStatus to avoid polling conflict
statusQuery: BOOLEANFALSE; -- did we request this status?
revisionQuery: BOOLEANFALSE; -- 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: BOOLEANFALSE; -- full page buffering mode
pageBufferFile: File.File; -- full page file
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];
PUBLIC Variables:
unlimitedAvailable: PUBLIC BOOLEANFALSE;
PUBLIC PROCEDUREs:
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
set up band buffers, etc.
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
BandBLTCreatePageTransfer: PUBLIC SAFE PROCEDURE [firstPlate: BOOLEAN] = TRUSTED BEGIN
END; -- BandBLTCreatePageTransfer
PageTransferSet: PUBLIC SAFE PROCEDURE[pageNumber: CARDINAL] = TRUSTED BEGIN
<< -- Forceout/Deactivate all of VM >> Needs to build bitmap!!!
pageBufferIndex ← 0;
WHILE pageBufferIndex <= pageBufferIndexLast DO
loopBandCount: CARDINALMIN[
pageBufferIndexLast - pageBufferIndex + 1, vmMaxBandRequest];
VM.MakeResident[
interval: [
page: VM.PageNumberForAddress[
PageBufferAddress[pageBufferIndex, 0]],
count: pagesPerBand * loopBandCount], returnWait: wait];
pageBufferIndex ← pageBufferIndex + loopBandCount;
ENDLOOP;
prefill band buffers from page
[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
PRIVATE PROCEDUREs:
Swap: PROCEDURE [UNSPECIFIED, UNSPECIFIED] RETURNS [UNSPECIFIED, UNSPECIFIED] = TRUSTED MACHINE CODE {};
BandBLTInternal: PROCEDURE = INLINE BEGIN
IF abortImaging OR (bandBLTTableInternal.bandlist ← BandBLT.BandBLT[bandBLTTableInternal]) = NIL
THEN BEGIN lastBand ← TRUE; bandLast ← band; END
ELSE BEGIN
switch page numbers of input & output leftover pages
[bandBLTTableInternal.writeLO, bandBLTTableInternal.readLO] ← Swap[
bandBLTTableInternal.readLO, bandBLTTableInternal.writeLO];
bandBLTTableInternal.bandlist ←
bandBLTTableInternal.bandlist + SIZE[endOfBand BandBLT.BlItem]; -- advance bandlist pointer for end of band marker
END;
mark current band ready for imaging and get address and index of next
[nextBand: band, nextBandAddress: bandBLTTableInternal.bandbuf] ←
LSEPFace.AdvanceBand[currentBand: band];
END; -- BandBLTInternal
BandCopyInternal: PROCEDURE = TRUSTED INLINE BEGIN
copy from page buffer to imaging band, by scan line scan lines in the buffer are each wordsPerScanLine words scan lines in the imaging band are each 256 words, offset ahead by 256 words-wordsPerScanLine
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};
mark current band ready for imaging and get address and index of next
[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
FORKed PROCEDUREs
HandleCommand: PROCEDURE = TRUSTED BEGIN
pops a command and acts on it, and notifies WatchCommandStatus that command has been sent if a response is expected.
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
wait till notified by HandleStatus of pageSync
[] ← 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
imaging got ahead of filling
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: BOOLEANFALSE;
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];
wait for completion of imaging
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).