RavenDriverImpl.mesa
Copyright Ó 1985, 1986, 1987 by Xerox Corporation. All rights reserved.
Tim Diebert: January 28, 1987 10:39:29 am PST
Rick Beach, November 25, 1985 8:18:04 am PST
Michael Plass, November 26, 1985 2:44:23 pm PST
DIRECTORY
Basics USING [bitsPerWord, DoubleShiftRight, LongMult],
CountedVM USING [Handle, SimpleAllocate],
FontTune USING [CreateFontTuner],
Imager USING [Context, metersPerInch, RotateT, ScaleT, SetPriorityImportant, TranslateT],
ImagerFastShow USING [Create],
ImagerPixelMap USING [DeviceRectangle, PixelMap, PixelMapRep, Clear],
ImagerRaster USING [FontTuner],
Loader USING [MakeProcedureResident, MakeGlobalFrameResident],
LSEPFace,
Process USING [Detach, Pause, MsecToTicks, Priority, GetPriority, priorityBackground, priorityFaultHandlers, priorityRealTime, SetPriority],
PrincOps USING [bitsPerWord, wordsPerPage, BBTableSpace, BBptr, PageCount],
PrincOpsUtils USING [AllocateNakedCondition, BITBLT, AlignedBBTable, GetClockPulses --, LongCopy --],
RavenCodes,
RavenDriver,
Rope USING [ROPE],
VM USING [Allocate, Interval, PageCount, PagesForWords, Pin ],
VMSideDoor USING [AssignSpecialRealMemory];
RavenDriverImpl: MONITOR
IMPORTS Basics, CountedVM, FontTune, Imager, ImagerFastShow, ImagerPixelMap, Loader, LSEPFace, Process, PrincOpsUtils, VM, VMSideDoor
EXPORTS RavenDriver
~ BEGIN OPEN RavenDriver;
myPixelMap: ImagerPixelMap.PixelMap ← [0, 0, 0, 0, 0, 0, NIL];
secondPixelMap: ImagerPixelMap.PixelMap ← [0, 0, 0, 0, 0, 0, NIL];
GetPrinterPixelMap: PUBLIC PROC RETURNS [pixelMap: ImagerPixelMap.PixelMap] = {RETURN[myPixelMap]};
MakePrinterPixelMap: PROC RETURNS [pixelMap: ImagerPixelMap.PixelMap] = BEGIN
bounds: ImagerPixelMap.DeviceRectangle ← [0, 0, (8*300+300/2), (11*300)];
numBands: NAT = ((8*300+300/2)+15)/16;
numLines: CARDINAL = numBands * sizeEachBand;
wordsPerLine: NAT ~ activeLength;
words: LONG CARDINAL ~ Basics.LongMult[wordsPerLine, numLines];
pages: CARDINAL = VM.PagesForWords[words];
vm: CountedVM.Handle ← CountedVM.SimpleAllocate[words];
interval: VM.Interval ~ vm.interval;
refRep: REF ImagerPixelMap.PixelMapRep ← NEW[ImagerPixelMap.PixelMapRep ← [
ref: vm, pointer: vm.pointer, words: vm.words,
lgBitsPerPixel: 0, rast: wordsPerLine, lines: numLines]];
FOR i: INT ← 0, i+400 UNTIL i >= interval.count DO -- only pin about 100K each time
VM.Pin[[page: interval.page+i, count: MIN[interval.count-i, 400]]];
Process.Pause[Process.MsecToTicks[500]]; -- wait a half second for Laundry process
ENDLOOP;
pixelMap.refRep ← refRep;
pixelMap.sMin ← 0;
pixelMap.fMin ← 0;
[pixelMap.sOrigin, pixelMap.fOrigin, pixelMap.sSize, pixelMap.fSize] ← bounds;
ImagerPixelMap.Clear[pixelMap];
END;
ContextFromPixelMap: PUBLIC PROC [pixelMap: ImagerPixelMap.PixelMap,
fontTunerParms: Rope.ROPENIL]
RETURNS [context: Imager.Context] = BEGIN
fontTuner: ImagerRaster.FontTuner ← NIL;
IF fontTunerParms # NIL THEN fontTuner ← FontTune.CreateFontTuner[fontTunerParms];
context ← ImagerFastShow.Create[pm: pixelMap, pixelsPerInch: RavenCodes.resolution[fast], pixelUnits: TRUE, fontTuner: fontTuner];
Imager.SetPriorityImportant[context, TRUE];
Imager.RotateT[context, -90.0];
Imager.TranslateT[context, [-(8*300+300/2), 0]];
Imager.ScaleT[context, RavenCodes.resolution[fast]/Imager.metersPerInch];
END;
lastPaperFeed: RavenCodes.PrinterCommand ← feed;
SetRegistration: PUBLIC PROCEDURE [registration: RavenRegistration] = TRUSTED BEGIN
DivideUp: PROCEDURE [divident, divisor: CARDINAL] RETURNS [quotient: CARDINAL] = TRUSTED INLINE BEGIN RETURN[quotient: (divident + divisor - 1) / divisor]; END;
sets up arguments for call which will set page offsets
LSEPFace.SetPageOffsets[
wordsFast: DivideUp[divident: registration.long * registrationTabSize,
divisor: PrincOps.bitsPerWord],
linesSlow: registration.short * registrationTabSize];
END; -- SetRegistration
lastBand: BOOL;
pageBufferIndex: CARDINAL; -- index to current band in page buffer
pageBufferIndexLast: CARDINAL; -- last meaningful band in page buffer
pageBufferBandBuffer: LONG POINTER; -- band buffer virtual address
bandBufferSize: PrincOps.PageCount = 16; -- From BandBLT
ScanLine: TYPE = [0..bandBufferSize); -- scan line index into a band
bandLast, band, firstBand: LSEPFace.Index;
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
dstBpl: INTEGER ~ PrincOps.wordsPerPage*Basics.bitsPerWord;
BandCopyInternal: PROCEDURE [pixelMap: ImagerPixelMap.PixelMap, pm: REF ImagerPixelMap.PixelMapRep] = 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
bandOffset: CARDLONG[pageBufferIndex] * LONG[pm.rast] *
LONG[LAST[ScanLine]];
sourceAddr: LONG POINTER ← pm.pointer + Basics.LongMult[pageBufferIndex, pm.rast*sizeEachBand];
bb^ ← [
dst: [word: pageBufferBandBuffer, bit: 0],
dstBpl: dstBpl,
src: [word: sourceAddr, bit: 0],
srcDesc: [srcBpl[pm.rast*Basics.bitsPerWord]],
height: sizeEachBand,
width: pixelMap.fSize,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]
];
PrincOpsUtils.BITBLT[bb];
FOR scanIndex: ScanLine IN [FIRST[ScanLine]..LAST[ScanLine]] DO
PrincOpsUtils.LongCopy[
from: PageBufferAddress[base, pageBufferIndex, scanIndex],
from: LOOPHOLE[pm.pointer + bandOffset + (scanIndex * LONG[pm.rast])],
nwords: activeLength,
to: LOOPHOLE[LOOPHOLE[pageBufferBandBuffer, LONG CARDINAL] + scanIndex * 256]];
ENDLOOP;
IF (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
dataOnPulses: ARRAY [0 .. 256) OF CARDALL[0];
PrintFromPixelMap: PUBLIC PROC [pixelMap: ImagerPixelMap.PixelMap,
copies: CARDINAL ← 1, paperFeed: RavenDriver.PaperFeed ← alternating] RETURNS [endingStatus: PrinterStatus, type: StatusType] = BEGIN
ENABLE ABORTED => printing ← FALSE;
timeout, error: BOOLFALSE;
old: Process.Priority ← Process.GetPriority[];
WaitReady: ENTRY PROC [] = INLINE BEGIN ENABLE UNWIND => NULL;
UNTIL ReadyStatus[currStatus] DO
WAIT newStatus ENDLOOP;
END;
WaitPageSync: ENTRY PROC [] = INLINE BEGIN ENABLE UNWIND => NULL;
UNTIL currStatus = pageSync OR ErrorStatus[currStatus] DO
WAIT newStatus;
IF ErrorStatus[currStatus] THEN {error ← TRUE; EXIT}; ENDLOOP;
END;
WaitBandEmpty: ENTRY PROC [band: LSEPFace.Index] = INLINE BEGIN
ENABLE UNWIND => NULL;
WHILE LSEPFace.BandFull[band] DO WAIT dataCondition^; ENDLOOP;
END;
paperTray: RavenCodes.PrinterCommand ← SELECT paperFeed FROM
bottom => feed,
top => feedTop,
alternating => IF lastPaperFeed = feed THEN feedTop ELSE feed,
ENDCASE => feed;
printing ← TRUE;
lastPaperFeed ← paperTray;
pageBufferIndexLast ← pixelMap.refRep.lines/16-1;
LSEPFace.PutCommand[LOOPHOLE[RavenCodes.PrinterCommand[solicitStatus]]];
WaitReady[];
IF error THEN GOTO OutErr;
[firstBand: band, firstBandAddress: pageBufferBandBuffer] ← LSEPFace.ResetBands[];
firstBand ← band;
pageBufferIndex ← 0;
lastBand ← FALSE;
THROUGH [0..bandBufferCount) UNTIL lastBand DO
BandCopyInternal[pixelMap, pixelMap.refRep];
dataOnPulses[pageBufferIndex] ← PrincOpsUtils.GetClockPulses[];
ENDLOOP;
BEGIN ENABLE UNWIND => Process.SetPriority[old];
Process.SetPriority[Process.priorityFaultHandlers];
LSEPFace.PutCommand[LOOPHOLE[paperTray]];
WaitPageSync[];
LSEPFace.StartImage[firstBand: firstBand];
Refill bands when they have been imaged until input is exhausted
UNTIL lastBand DO
WaitBandEmpty[band];
BandCopyInternal[pixelMap, pixelMap.refRep];
dataOnPulses[pageBufferIndex] ← PrincOpsUtils.GetClockPulses[];
ENDLOOP;
LSEPFace.LastBand[bandLast]; -- indicate that last band has been filled
WaitBandEmpty[bandLast];
IF LSEPFace.BandOverrun[] THEN GOTO Out;
printing ← FALSE;
EXITS Out => {Process.SetPriority[old]; RETURN [ropeStatus[currStatus], error]};
END;
Process.SetPriority[old];
RETURN [ropeStatus[noStatus], normal];
EXITS OutErr => {RETURN [ropeStatus[currStatus], error]};
END;
currStatus: RavenCodes.PrinterStatus ← noStatus;
mySP: REF StatusProc ← NIL;
printing: BOOLFALSE;
newStatus: CONDITION;
SetScanLineLength: PUBLIC SAFE PROCEDURE [scanLineLength: (0..PrincOps.wordsPerPage]] = TRUSTED BEGIN
LSEPFace.SetScanLineLength[scanLineLength];
END;
MonitorRavenStatus: PROC [] = BEGIN
WaitStatus: ENTRY PROC [] = INLINE BEGIN ENABLE UNWIND => NULL;
ready: BOOLFALSE;
UNTIL ready DO
WAIT statusCondition^; ready ← TRUE; ENDLOOP;
END;
Note: ENTRY PROC [] = INLINE {ENABLE UNWIND => NULL; BROADCAST newStatus};
messageInternal: Message ← commandStatusFault;
Process.SetPriority[Process.priorityRealTime];
DO -- Forever
WaitStatus[];
LSEPFace.PutCommand[LOOPHOLE[RavenCodes.PrinterCommand[solicitStatus]]];
currStatus ← LOOPHOLE[LSEPFace.GetStatus[]];
IF currStatus = pageSync THEN {Note[]; LOOP};
SELECT currStatus FROM
statusOverRun, noStatus, parityError, unrecognizedCommand, illegalSequence, statusError => -- read status and try again
IF messageInternal = aboutToDozeOff THEN LOOP; -- ignore death throes
IN [key0..keyOffLine] => LOOP;
warming, standBy, feederFault, registrationJam, fuserJam, noExit, interlockOpen, fuserCold, feedTraysNotEngaged, tonerLow, goingOffLine, offLine, outputTrayFull, aboutToDozeOff => BEGIN
set message and broadcast newMessage
messageInternal ← SELECT currStatus FROM
warming, fuserCold => fuserUnderTemperature,
standBy => ok,
feederFault => preRegistrationFault,
registrationJam => postRegistrationJam,
fuserJam => preExitJam,
noExit => postExitJam,
interlockOpen => doorOpen,
feedTraysNotEngaged => traysUnlatched,
tonerLow => tonerLow,
goingOffLine, offLine => offLine,
outputTrayFull => outputTrayFull,
ENDCASE => aboutToDozeOff;
END;
ENDCASE => {Note[]; LOOP};
IF NOT printing AND mySP # NIL THEN Process.Detach[FORK Send[]];
Note[];
ENDLOOP;
END;
Send: PROC [] = BEGIN
Process.SetPriority[Process.priorityBackground];
mySP[ropeStatus[currStatus], normal];
END;
Message: TYPE = {traysUnlatched, preRegistrationFault, postRegistrationJam, preExitJam, postExitJam, doorOpen, outputTrayFull, tonerLow, aboutToDozeOff, fuserUnderTemperature, imageFault, commandStatusFault, offLine, ok};
ReadyStatus: PROC [status: RavenCodes.PrinterStatus] RETURNS [ready: BOOL] = INLINE BEGIN
ready ← SELECT status FROM
standBy, readyToFeed => TRUE,
ENDCASE => FALSE;
END;
ErrorStatus: PROC [status: RavenCodes.PrinterStatus] RETURNS [error: BOOL] = INLINE BEGIN
error ← SELECT status FROM
feederFault, registrationJam, fuserJam, noExit, interlockOpen, fuserCold, feedTraysNotEngaged, tonerLow, goingOffLine, offLine, aboutToDozeOff => TRUE,
ENDCASE => FALSE;
END;
RegisterStatusProc: PUBLIC ENTRY PROC [sp: StatusProc] = {mySP ← NEW[StatusProc ← sp]};
UnRegisterStatusProc: PUBLIC ENTRY PROC [sp: StatusProc] = {mySP ← NIL};
WakeUp: PUBLIC PROCEDURE[] = BEGIN
LSEPFace.PutCommand[LOOPHOLE[RavenCodes.PrinterCommand[solicitStatus]]]; -- Jump start the Raven
END;
bandBufferCount: LSEPFace.BandBufferCount ← 3;
wordsPerBand: CARDINAL = sizeEachBand * PrincOps.wordsPerPage;
sizeEachBand: CARDINAL = 16;
pagesNeedForBands: VM.PageCount = LSEPFace.MaxBands * sizeEachBand + 20;
vm: VM.Interval;
activeLength: (0..PrincOps.wordsPerPage] ← ((11*300)+15)/16;
statusCondition: LONG POINTER TO CONDITIONNIL; statusMask: WORD ← 0;
dataCondition: LONG POINTER TO CONDITIONNIL; dataMask: WORD ← 0;
Init: PROC [] = BEGIN
vm ← VM.Allocate[pagesNeedForBands];
VMSideDoor.AssignSpecialRealMemory[vm]; -- Move to low core and Pin
LSEPFace.AllocateBands[vm.page, bandBufferCount, sizeEachBand, 1];
SetScanLineLength[activeLength];
myPixelMap ← MakePrinterPixelMap[];
secondPixelMap ← MakePrinterPixelMap[];
Loader.MakeProcedureResident[PrintFromPixelMap];
Loader.MakeGlobalFrameResident[PrintFromPixelMap];
[statusCondition, statusMask] ← PrincOpsUtils.AllocateNakedCondition[];
[dataCondition, dataMask] ← PrincOpsUtils.AllocateNakedCondition[];
Process.SetTimeout[dataCondition, Process.SecondsToTicks[20]];
LSEPFace.SetInterruptMasks[0, statusMask, dataMask];
LSEPFace.PutCommand[LOOPHOLE[RavenCodes.PrinterCommand[solicitStatus]]]; -- Jump start the Raven
Process.Detach[FORK MonitorRavenStatus[]]; -- Up to realTime
END;
ropeStatus: ARRAY RavenCodes.PrinterStatus OF PrinterStatus ← ALL[NIL];
ropeStatus[noStatus] ← "No status";
ropeStatus[key0] ← "key0";
ropeStatus[key1] ← "key1";
ropeStatus[key2] ← "key2";
ropeStatus[key3] ← "key3";
ropeStatus[key4] ← "key4";
ropeStatus[key5] ← "key5";
ropeStatus[key6] ← "key6";
ropeStatus[key7] ← "key7";
ropeStatus[key8] ← "key8";
ropeStatus[key9] ← "key9";
ropeStatus[keyClear] ← "keyClear";
ropeStatus[keyTest] ← "keyTest";
ropeStatus[keyOnLine] ← "keyOnLine";
ropeStatus[keyOffLine] ← "keyOffLine";
ropeStatus[warming] ← "Warming";
ropeStatus[standBy] ← "Ready";
ropeStatus[feederFault] ← "Feeder Fault";
ropeStatus[registrationJam] ← "Registration Jam";
ropeStatus[fuserJam] ← "Fuser Jam";
ropeStatus[noExit] ← "No Exit";
ropeStatus[interlockOpen] ← "Interlock Open";
ropeStatus[fuserCold] ← "Fuser Cold";
ropeStatus[feeding] ← "Feeding";
ropeStatus[readyToFeed] ← "Ready To Feed";
ropeStatus[displayAcknowledge] ← "displayAcknowledge";
ropeStatus[parityError] ← "parityError";
ropeStatus[unrecognizedCommand] ← "illegalCharacter";
ropeStatus[illegalSequence] ← "illegalSequence";
ropeStatus[feedTraysNotEngaged] ← "Paper Tray Open or Out of Paper";
ropeStatus[pageSync] ← "pageSync";
ropeStatus[pageAtOutputTray] ← "pageAtOutputTray";
ropeStatus[tonerLow] ← "Toner Low";
ropeStatus[goingOffLine] ← "goingOffLine";
ropeStatus[offLine] ← "offLine";
ropeStatus[outputTrayFull] ← "outputTrayFull";
ropeStatus[aboutToDozeOff] ← "Low Power Mode";
ropeStatus[statusError] ← "statusError";
ropeStatus[statusOverRun] ← "statusOverRun";
Init[];
END.