RavenControlImpl.mesa
Copyright Ó Xerox Corporation 1985, 1986, 1987. All rights reserved.
last edited by prochaska 14-May-86 14:00:10
Tim Diebert: March 31, 1987 9:47:22 am PST
DIRECTORY
Basics USING [LongMult],
Interrupt USING [Initialize, Object, Wait],
LSEPFace USING [AdvanceBand, AllocateBands, BandBufferCount, BandFull, BandOverrun, GetStatus, Index, InitializeCleanUp, LastBand, PutCommand, SetInterruptMasks, SetScanLineLength, StartImage, ResetBands],
PrincOps USING [PageCount, wordsPerPage],
PrincOpsUtils USING [LongCopy],
Process USING [Detach, MsecToTicks, Pause, priorityFaultHandlers, priorityRealTime, SetPriority, SetTimeout],
Queue USING [Initialize, Object, Pop, Push],
RavenCodes USING [PrinterCommand, PrinterStatus],
RavenControl USING [ConsoleKey, EngineEvent, EngineStatus, LogItem, PlateStatus, PaperTray, PaperTraySize, PaperStacking],
SharedQueue USING [GetCurrentHead, Initialize, Object, Pop, Push],
Synchronizer USING [Broadcast, Initialize, Notify, Object, Wait],
VM USING [AddressForPageNumber, Allocate, Interval, nullInterval, -- PageNumberForAddress, -- Pin];
RavenControlImpl:
PROGRAM
IMPORTS Basics, Interrupt, LSEPFace, PrincOpsUtils, Process, Queue, SharedQueue, Synchronizer, VM
EXPORTS RavenControl = BEGIN
Band: TYPE = ARRAY [0 .. bandBufferSize * PrincOps.wordsPerPage) OF WORD;
EventContext: PUBLIC TYPE = CARDINAL;
ScanLine: TYPE = [0..bandBufferSize); -- scan line index into a band
bandBufferSize: PrincOps.PageCount = 16; -- From BandBLT
maxBands: CARDINAL = 160; -- 8.5" * 300BitsPer" / 16BitsPerWord
vmMaxBandRequest: CARDINAL = 14; -- 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
Synchronizer Objects (monitored records used as conditions):
commandSent, engineEvent, newStatus, pageSync, statusReceived, imagingComplete:
Synchronizer.Object;
Interrupt Objects (monitored records used as interrupt conditions):
controlInt, imageInt, statusInt: Interrupt.Object;
Queue Objects (monitored records used as queues):
commandQ, consoleQ, logQ, turnaroundQ: Queue.Object;
eventQ: SharedQueue.Object;
engineState: {okay, error} ← okay;
transferStatus: {ready, notReady} ← notReady;
statusInternal: RavenControl.EngineStatus ← communicationFault;
paperTrayLast: RavenControl.PaperTray ← bottom; -- last tray fed from
paperTrayOk: ARRAY RavenControl.PaperTray OF BOOLEAN ← ALL[TRUE]; -- status of paper trays
paperSizeInternal: RavenCodes.PrinterStatus;
abortImaging: BOOLEAN ← FALSE;
flushPrinter: BOOLEAN ← FALSE;
lastBand: BOOLEAN;
imagingActive: BOOLEAN ← FALSE;
statusQuery: BOOLEAN ← FALSE; -- did we send a solicitStatus command
loopbackMode: BOOLEAN ← FALSE; -- server Loop Back diagnostic test
band, bandFirst, bandLast: LSEPFace.Index;
bandBufferCount: LSEPFace.BandBufferCount;
bandLowCore: VM.Interval;
wordsPerScanLine: (0..PrincOps.wordsPerPage]; -- current words per scan line
pagesPerBand: CARDINAL; -- number of pages in each page buffer band
printUnlimitedMode: BOOLEAN ← TRUE; -- full page buffering mode
pageBufferInterval: CountedVM.Handle; -- 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
for debugging
EventLogIndex: TYPE = [0..32);
eventLogIndex: EventLogIndex ← 0;
eventLog: ARRAY EventLogIndex OF RavenControl.EngineEvent ← ALL[idle];
unlimitedAvailable: PUBLIC BOOLEAN ← FALSE;
Initialize:
PUBLIC
SAFE
PROCEDURE [bufferSize: PrincOps.PageCount,
enableUnlimited:
BOOLEAN] =
TRUSTED
BEGIN
initialize interrupt objects for LSEPFace's interrupt masks
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];
start the cleanup proc
Process.Detach[FORK LSEPFace.InitializeCleanUp];
set up the interrupt interface to the head
LSEPFace.SetInterruptMasks[control: controlMask, status: statusMask, data: imageMask];
initialize queue objects
Queue.Initialize[@commandQ];
Queue.Initialize[@logQ];
Queue.Initialize[@turnaroundQ];
Queue.Initialize[@consoleQ];
SharedQueue.Initialize[queue: @eventQ, enableAbort: TRUE, enableTimeout: TRUE, lapse: 20000]; -- event timeout 20 seconds
initialize synchronizer objects
Synchronizer.Initialize[synchronizer: @commandSent, enableAbort: TRUE, enableTimeout: FALSE];
Synchronizer.Initialize[synchronizer: @engineEvent, enableAbort: TRUE, enableTimeout: TRUE, lapse: 30000];
Synchronizer.Initialize[synchronizer: @newStatus, enableAbort: TRUE, enableTimeout: FALSE];
Synchronizer.Initialize[synchronizer: @pageSync, enableAbort: TRUE, enableTimeout: FALSE];
Synchronizer.Initialize[synchronizer: @statusReceived, enableAbort: TRUE, enableTimeout: TRUE, lapse: 6000]; -- commands should respond within 5 seconds
Synchronizer.Initialize[synchronizer: @imagingComplete, enableAbort: TRUE, enableTimeout: TRUE, lapse: 12000];
set up band buffers, etc.
bandBufferCount ← bufferSize / bandBufferSize;
bandLowCore ← VM.Allocate[bufferSize + bandBufferPadding];
VMSideDoor.AssignSpecialRealMemory[bandLowCore]; -- Move to low core and Pin
LSEPFace.AllocateBands[bandVirtualPageNumber: bandLowCore.page,
nBands: bandBufferCount, sizeEachBand: bandBufferSize, slop: 1];
create the full page buffer interval
pageBufferInterval ← CountedVM.SimpleAllocate[bandBufferSize * maxBands];
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;
start the printing processes
Process.Detach[FORK HandleCommand]; -- priority = 6
Process.Detach[FORK HandleImage]; -- priority = 5
Process.Detach[FORK HandleStatus]; -- priority = 6
Process.Detach[FORK WatchCommandStatus]; -- priority = 6
Process.Detach[FORK WatchImaging]; -- priority = 6
do a get status to querry the printer
SendEngineCommand[solicitStatus];
SendEngineCommand[solicitPaperSize];
END; -- Initialize
GetEngineStatus:
PUBLIC
SAFE
PROCEDURE
RETURNS [RavenControl.EngineStatus] =
TRUSTED
BEGIN
returns current Raven engine status
RETURN[IF (statusInternal = okay OR statusInternal = tonerLow) AND flushPrinter THEN okayFlushRequired ELSE statusInternal];
END; -- GetEngineStatus
WaitEngineStatus:
PUBLIC
SAFE
PROCEDURE
RETURNS [RavenControl.EngineStatus] =
TRUSTED {[] ← Synchronizer.Wait[@newStatus]; RETURN[GetEngineStatus[]]}; -- WaitEngineStatus
GetPaperTrayStatus:
PUBLIC
SAFE
PROCEDURE [tray: RavenControl.PaperTray]
RETURNS [okay:
BOOLEAN] =
TRUSTED
BEGIN
returns the status of paper in the desired paper tray
RETURN[okay: paperTrayOk[tray]];
END;
GetPaperTraySize:
PUBLIC
SAFE
PROC
RETURNS [bottom, top: RavenControl.PaperTraySize] =
TRUSTED
BEGIN
returns the staus of the desired paper tray
SELECT paperSizeInternal
FROM
paperSmallSmall => RETURN[small, small];
paperSmallLarge => RETURN[small, large];
paperLargeSmall => RETURN[large, small];
paperLargeLarge => RETURN[large, large];
ENDCASE => RETURN[unknown, unknown];
END;
WaitEngineEvent:
PUBLIC
SAFE
PROCEDURE [eventContext:
REF EventContext]
RETURNS [event: RavenControl.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;
WaitConsoleKey: PUBLIC SAFE PROC RETURNS [key: RavenControl.ConsoleKey] = TRUSTED {RETURN[Queue.Pop[@consoleQ]]};
WaitLogItem: PUBLIC SAFE PROCEDURE RETURNS [RavenControl.LogItem] = TRUSTED {RETURN[Queue.Pop[@logQ]]};
Feed:
PUBLIC
SAFE
PROCEDURE [tray: RavenControl.PaperTray, stacking: RavenControl.PaperStacking] =
TRUSTED
BEGIN
SendEngineCommand[
SELECT
TRUE
FROM
tray = bottom AND stacking = aligned => feed,
tray = top AND stacking = aligned => feedTop,
tray = bottom AND stacking = offset => feedOffset,
tray = top AND stacking = offset => feedTopOffset,
ENDCASE => ERROR];
END; -- Feed
SendEngineCommand:
PUBLIC
SAFE
PROCEDURE [cmd: RavenCodes.PrinterCommand] =
TRUSTED BEGIN Queue.Push[@commandQ, cmd]; END; -- SendEngineCommand
SetScanLineLength:
PUBLIC
SAFE
PROCEDURE [scanLineLength: (0..PrincOps.wordsPerPage]] =
TRUSTED
BEGIN
LSEPFace.SetScanLineLength[scanLineLength];
wordsPerScanLine ← scanLineLength;
pagesPerBand ← ((scanLineLength * 16) + PrincOps.wordsPerPage - 1) / PrincOps.wordsPerPage;
END;
BandBLTTransferReady:
PUBLIC
SAFE
PROCEDURE =
TRUSTED
BEGIN
IF imagingActive THEN
Runtime.CallDebugger["imagingActive at RavenControl.BandBLTTransferReady"L];
IF transferStatus = ready THEN
Runtime.CallDebugger[
"transferStatus = ready at RavenControl.BandBLTTransferReady"L];
LOOPHOLE[Basics.LongMult[
bandBLTTableInternal.readLO, PrincOps.wordsPerPage], LONG POINTER]^ ←
BandBLT.BlItem[endOfBand[]]; -- put end of band mark at beginning of readLO page
[firstBand: band, firstBandAddress: bandBLTTableInternal.bandbuf] ←
LSEPFace.ResetBands[];
bandFirst ← band;
lastBand ← FALSE;
THROUGH [0..bandBufferCount) UNTIL lastBand DO BandBLTInternal; ENDLOOP;
printUnlimitedMode ← FALSE;
transferStatus ← ready;
BroadcastEngineEvent[transferReady];
END; -- BandBLTTransferReady
BandBLTTransferCreatePage:
PUBLIC
SAFE
PROCEDURE [firstPlate:
BOOLEAN] =
TRUSTED
BEGIN
IF imagingActive THEN Runtime.CallDebugger[
"imagingActive at RavenControl.BandBLTTransferCreatePage"L];
IF transferStatus = ready THEN Runtime.CallDebugger[
"transferStatus = ready at RavenControl.BandBLTTransferCreatePage"L];
LOOPHOLE[Basics.LongMult[bandBLTTableInternal.readLO, PrincOps.wordsPerPage], LONG POINTER]^ ← BandBLT.BlItem[endOfBand[]]; -- put end of band mark at beginning of readLO page
reset pageBufferIndexLast if first plate
IF firstPlate THEN pageBufferIndexLast ← 0;
create full page bitmap in pageBuffer
IF NOT unlimitedAvailable THEN
Runtime.CallDebugger["unlimitedMode but not enough RM or disk"L];
Space.Activate[interval: [
pointer: pageBufferInterval.pointer,
count: pagesPerBand * pageBufferActivateCount]];
create bands in a reserved memory band buffer (BandBLT can't handle bandbuffer out of first 64K)
[firstBandAddress: bandBLTTableInternal.bandbuf] ← LSEPFace.ResetBands[];
lastBand ← FALSE;
FOR pageBufferIndex IN [0..maxBands) UNTIL lastBand DO
activate ahead
IF pageBufferIndex + pageBufferActivateCount < maxBands THEN
Space.Activate[
interval: [
pointer: PageBufferAddress[pageBufferIndex + pageBufferActivateCount, 0],
count: pagesPerBand]];
zero the band if not yet used on this page
IF pageBufferIndex > pageBufferIndexLast OR firstPlate THEN
LOOPHOLE[bandBLTTableInternal.bandbuf, LONG POINTER TO Band]^ ← ALL[0];
do the BandBLT
IF (bandBLTTableInternal.bandlist ← BandBLT.BandBLT[bandBLTTableInternal]) = NIL
THEN BEGIN
lastBand ← TRUE;
pageBufferIndexLast ← MAX[pageBufferIndex, pageBufferIndexLast];
END
ELSE BEGIN
switch page numbers of input & output leftover pages
[bandBLTTableInternal.writeLO, bandBLTTableInternal.readLO] ← Swap[
bandBLTTableInternal.readLO, bandBLTTableInternal.writeLO];
advance bandlist pointer for end of band marker
bandBLTTableInternal.bandlist ←
bandBLTTableInternal.bandlist + SIZE[endOfBand BandBLT.BlItem];
END;
copy the band from the BandBLT band to the page buffer, by scan line
scan lines created by BandBLT are each 256 words, offset ahead by 256 words-wordsPerScanLine
scan lines in the page buffer are each wordsPerScanLine words
FOR scanIndex: ScanLine IN [FIRST[ScanLine]..LAST[ScanLine]] DO
PrincOpsUtils.LongCopy[
from: LOOPHOLE[LOOPHOLE[bandBLTTableInternal.bandbuf, LONG CARDINAL] + scanIndex * 256],
nwords: wordsPerScanLine,
to: PageBufferAddress[pageBufferIndex, scanIndex]];
ENDLOOP;
ENDLOOP;
END; -- BandBLTTransferCreatePage
PageTransferSet:
PUBLIC
SAFE
PROCEDURE[pageNumber:
CARDINAL] =
TRUSTED
BEGIN
<< -- Forceout/Deactivate all of VM >> Needs to build bitmap!!!
make the page buffer resident, small counts to not trigger Pilot VM bug
pageBufferIndex ← 0;
WHILE pageBufferIndex <= pageBufferIndexLast
DO
loopBandCount:
CARDINAL ←
MIN[
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
RunTurnaroundTest:
PUBLIC
SAFE
PROCEDURE
RETURNS [ok:
BOOLEAN] =
TRUSTED
BEGIN
codeOut, codeIn: CARDINAL [0..177B];
ok ← TRUE;
loopbackMode ← 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;
loopbackMode ← FALSE;
SendEngineCommand[solicitStatus]; -- make sure command/status polling continues
Process.Pause[Process.MsecToTicks[200]]; -- wait for command to be sent
END;
Swap:
PROCEDURE [
UNSPECIFIED,
UNSPECIFIED]
RETURNS [
UNSPECIFIED,
UNSPECIFIED] =
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 =
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
BroadcastEngineEvent:
PROCEDURE [event: RavenControl.EngineEvent] =
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
PageBufferAddress:
PROCEDURE [bandIndex:
CARDINAL, scanLine: ScanLine]
RETURNS [
LONG
POINTER] =
INLINE BEGIN
pointer stuff here as the compiler is unable to handle arrays of LONG arrays
RETURN[LOOPHOLE[VM.AddressForPageNumber[pageBufferInterval.page] + Basics.LongMult[bandIndex, pagesPerBand * 256] +
LONG[scanLine * wordsPerScanLine]]];
END; -- PageBufferAddress
SetEngineStatus:
PROCEDURE [status: RavenControl.EngineStatus] =
BEGIN
IF statusInternal # status
OR status = okay
THEN
{statusInternal ← status; Synchronizer.Broadcast[@newStatus]};
END; -- SetEngineStatus
HandleCommand:
PROCEDURE =
BEGIN
pops a command and acts on it, and notifies WatchCommandStatus that command has been sent if a response is expected.
cmd: RavenCodes.PrinterCommand;
Process.SetPriority[Process.priorityRealTime];
DO
-- forever
cmd ← Queue.Pop[@commandQ]; -- waits till queue is non-empty
IF loopbackMode
THEN Synchronizer.Notify[@commandSent]
ELSE BEGIN
SELECT cmd
FROM
beepShort, beepLong => NULL; -- no response
goToSleep =>
BEGIN
Queue.Push[@consoleQ, RavenCodes.PrinterStatus.key1];
Queue.Push[@consoleQ, RavenCodes.PrinterStatus.key2];
Queue.Push[@consoleQ, RavenCodes.PrinterStatus.keyTest]; -- ADP AR 4030
SetEngineStatus[lowPowerMode]; -- no response, post new status
END;
ENDCASE => Synchronizer.Notify[@commandSent];
SELECT cmd
FROM
solicitStatus => statusQuery ← TRUE;
feed, feedOffset => paperTrayLast ← bottom;
feedTop, feedTopOffset => paperTrayLast ← top;
solicitPaperSize => paperSizeInternal ← LOOPHOLE[0]; -- reset paper tray sizes to unknown
ENDCASE => NULL;
Queue.Push[@logQ, RavenControl.LogItem[command[cmd]]];
END;
LSEPFace.PutCommand[LOOPHOLE[cmd]]; -- send the command
Interrupt.Wait[@controlInt]; -- wait for IOP to send
IF NOT loopbackMode THEN Process.Pause[Process.MsecToTicks[100]]; -- allow IOT time to think
ENDLOOP; -- forever
END; -- HandleCommand
HandleImage:
PROCEDURE =
BEGIN
waits until a plate is ready, then calls for bands to be filled and imaged
WaitBandEmpty:
PROCEDURE [thisBand: LSEPFace.Index] =
INLINE BEGIN
WHILE LSEPFace.BandFull[thisBand] DO Interrupt.Wait[@imageInt]; ENDLOOP;
wait for band to be imaged
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, RavenControl.LogItem[plateStatus[pageSyncMiss]]];
LOOP;
END;
imagingActive ← TRUE;
LSEPFace.StartImage[bandFirst];
refill bands when they have been imaged until input is exhausted
IF printUnlimitedMode
THEN UNTIL lastBand DO WaitBandEmpty[band]; BandCopyInternal; ENDLOOP
ELSE UNTIL lastBand DO WaitBandEmpty[band]; BandBLTInternal; 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 LSEPFace.BandOverrun[]
THEN BEGIN
imaging got ahead of filling
BroadcastEngineEvent[imagedOverrun];
Queue.Push[@logQ, RavenControl.LogItem[plateStatus[bandOverrun]]];
END
ELSE BroadcastEngineEvent[imaged];
ENDLOOP; -- forever
END; -- HandleImage
HandleStatus:
PROCEDURE =
BEGIN
wait for status to be set and act accordingly
sts: RavenCodes.PrinterStatus;
loopbackPlug: BOOLEAN ← FALSE; -- to avoid trashing loopback test
Process.SetPriority[Process.priorityRealTime];
DO
-- forever
Interrupt.Wait[@statusInt]; -- wait for status from IOT
sts ← LOOPHOLE[LSEPFace.GetStatus[]]; -- get received status
IF loopbackMode
THEN BEGIN
Synchronizer.Notify[@statusReceived]; -- something was received
Queue.Push[@turnaroundQ, sts];
LOOP;
END;
SELECT sts
FROM
noStatus, statusError, statusOverRun =>
-- not legit status
IF statusInternal = lowPowerMode THEN LOOP; -- ignore completely if printer is off
LOOPHOLE[RavenCodes.PrinterCommand[solicitStatus]] => loopbackPlug ← TRUE;
IN [key0..LOOPHOLE[RavenCodes.PrinterCommand[displayBlank]]] => NULL; -- not responses to commands
ENDCASE => Synchronizer.Notify[@statusReceived]; -- WatchCommandStatus waiting on it
IF
NOT statusQuery
THEN
-- events are only if we didn't ask
SELECT sts
FROM
pageSync =>
BEGIN
-- handle this status first for better performance
Synchronizer.Broadcast[@pageSync];
BroadcastEngineEvent[feeding]; -- also used as the feeding status
IF imagingActive
AND transferStatus = ready
THEN
BEGIN
-- band overrun, still imaging
BroadcastEngineEvent[pageSyncMiss];
Queue.Push[@logQ, RavenControl.LogItem[plateStatus[pageSyncMiss]]];
END;
END;
standBy =>
BEGIN
-- printer is okay or after last page
BroadcastEngineEvent[idle];
IF engineState = error
THEN
-- state was error, now okay
SendEngineCommand[solicitPaperSize]; -- get paper size
engineState ← okay; -- set to error in BroadcastEngineEvent
END;
readyToFeed => BroadcastEngineEvent[readyToFeed];
pageAtOutputTray => BroadcastEngineEvent[pageDelivery];
feederFault =>
BEGIN
IF imagingActive THEN abortImaging ← TRUE;
paperTrayOk[paperTrayLast] ← FALSE;
BroadcastEngineEvent[feedError];
END;
fuserCold, goingOffLine, outputTrayFull => BroadcastEngineEvent[softError];
registrationJam, fuserJam, noExit, interlockOpen, aboutToDozeOff =>
BEGIN
IF imagingActive THEN abortImaging ← TRUE;
BroadcastEngineEvent[hardError];
END;
feedTraysNotEngaged => BroadcastEngineEvent[softError];
ENDCASE => NULL;
SELECT sts
FROM
noStatus, keyOnLine, parityError, unrecognizedCommand, illegalSequence,
LOOPHOLE[57H], -- B1 online
statusError, statusOverRun => -- read status and try again
SendEngineCommand[solicitStatus];
standBy =>
BEGIN
-- printer is okay or after last page
IF imagingActive
THEN BEGIN
-- flush required to finish imaging
abortImaging ← TRUE;
flushPrinter ← TRUE;
END;
END;
interlockOpen, feedTraysNotEngaged => paperTrayOk ← ALL[TRUE];
IN [paperSmallSmall..paperLargeLarge] => paperSizeInternal ← sts;
IN [key0..keyOffLine] =>
IF NOT loopbackPlug THEN Queue.Push[@consoleQ, sts];
ENDCASE => NULL;
log the status
Queue.Push[@logQ, RavenControl.LogItem[printerStatus[sts]]];
SELECT sts
FROM
warming, standBy, feederFault, registrationJam, fuserJam, noExit, interlockOpen, fuserCold, feedTraysNotEngaged, tonerLow, goingOffLine, offLine, outputTrayFull, aboutToDozeOff =>
BEGIN
meaningful engine statuses
loopbackPlug ← FALSE; -- not from loopback plug
IF statusInternal = communicationFault THEN SendEngineCommand[displayBlank];
IF sts = aboutToDozeOff
THEN
BEGIN
-- force engine out of repair mode
Queue.Push[@consoleQ, RavenCodes.PrinterStatus.key1];
Queue.Push[@consoleQ, RavenCodes.PrinterStatus.key2];
Queue.Push[@consoleQ, RavenCodes.PrinterStatus.keyTest];
END; -- ADP AR 4030
SetEngineStatus[
SELECT sts
FROM
warming => warming,
standBy => okay,
feederFault => preRegistrationFault,
registrationJam => postRegistrationJam,
fuserJam => preExitJam,
noExit => postExitJam,
interlockOpen => doorOpen,
fuserCold => warming,
feedTraysNotEngaged => traysUnlatched,
tonerLow => tonerLow,
goingOffLine, offLine => offline,
outputTrayFull => outputTrayFull,
aboutToDozeOff => lowPowerMode,
ENDCASE => ERROR];
END;
ENDCASE => NULL;
statusQuery ← FALSE;
ENDLOOP; -- forever
END; -- HandleStatus
WatchCommandStatus:
PROCEDURE =
BEGIN
commandStatusTimeout: BOOLEAN;
wait for notification of command being sent, then wait for a timeout
or notification on status received
Process.SetPriority[Process.priorityRealTime];
DO
-- forever
[] ← Synchronizer.Wait[@commandSent]; -- notification by HandleCommand
commandStatusTimeout ← Synchronizer.Wait[@statusReceived]; -- notification by HandleStatus
IF commandStatusTimeout
THEN
IF loopbackMode
THEN Queue.Push[@turnaroundQ, 200B] -- make turnaround test fail
ELSE BEGIN
SendEngineCommand[solicitStatus];
display L4 on printer panel (if possible)
SendEngineCommand[displayL];
SendEngineCommand[display4];
IF statusInternal # communicationFault
THEN BEGIN
SetEngineStatus[communicationFault];
BroadcastEngineEvent[hardError];
Queue.Push[@logQ, RavenControl.LogItem[softwareStatus[communicationFault]]];
END;
END;
ENDLOOP; -- forever
END; -- WatchCommandStatus
WatchImaging:
PROCEDURE =
BEGIN
Process.SetPriority[Process.priorityRealTime];
DO
-- forever
wait till notified by HandleStatus of pageSync
[] ← 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
SetEngineStatus[imageFault1];
BroadcastEngineEvent[hardError];
Queue.Push[@logQ, RavenControl.LogItem[softwareStatus[imageFault1]]];
END;
END;
ENDLOOP; -- forever
END; -- WatchImaging
21-Apr-85 22:02:59 / Strickberger / Created for Raven engine driver redesign (compatable with old RavenFace).
27-Jun-85 17:52:24 / Strickberger / Updated for multi-plate unlimited printing. Updated for Pilot 12.0. Always broadcast newStatus if status = okay. Don't notify statusRecieived if bad status. Fix priority usage. Make event timeout 30 seconds. Fix TransferRelease to not keep last band resident.
12-Aug-85 23:02:26 / Strickberger / Divide pageBuffer into scan lines to save RM on 8.5x11 pages. Update for Euclid interfaces. FixArrows.
19-Sep-85 18:58:22 / Strickberger / Added enableUnlimited parameter to Initialize. Properly handle Volume.InsufficientSpace and Space.InsufficientSpace in Initialize.
16-Oct-85 23:45:19 / Strickberger / Initialize paperTrayLast to avoid Address Fault if startup with feederFault status (AR22059).
2-Dec-85 1:29:52 / Strickberger / Abort imaging if feederFault status - B1 printers turn off laser (AR23075). Don't send solicitPaperSize if statusQuery (AR23076). Don't send solicitStatus or put stuff on console queue if loopbackPlug - avoid trashing loopback test (AR23112). Send solicitStatus if B1 onLine (57H) (AR23113).
19-Dec-85 11:26:46 / Strickberger / Clear imagingActive and abortImaging before broadcasting imagingComplete, possible race conditions (AR23371). Send solicitStatus after turnaround test (AR23115).
21-Feb-86 17:13:40 / Strickberger / Use pageSync status to BroadcastEngineEvent[feeding] instead of feeding status (AR3721).
11-Apr-86 16:48:44 / Strickberger / 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. (AR3999).
5-May-86 0:38:26 / Strickberger / Increase imagingComplete timeout to 12 seconds to avoid image faults on band overrun pages (AR4155). Broadcast pageSyncMiss if page still imaging at pageSync.
14-May-86 14:00:10 / Prochaska / Modified WaitEngineEvent[], BroadcastEngineEvent[] to use SharedQueue; Added SetToCurrentEventContext[].