RavenDriverImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Tim Diebert: January 22, 1987 12:18:29 pm PST
Rick Beach, November 25, 1985 8:18:04 am PST
Michael Plass, November 26, 1985 2:44:23 pm PST
DIRECTORY
Basics USING [DoubleShiftRight, LongMult, bitsPerWord],
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],
Process USING [Detach, Pause, MsecToTicks, Priority, GetPriority, priorityBackground, priorityFaultHandlers, priorityRealTime, SecondsToTicks, SetPriority, SetTimeout],
PrincOps USING [bitsPerWord, wordsPerPage, BBTableSpace, BBptr],
PrincOpsUtils USING [BITBLT, AlignedBBTable, AllocateNakedCondition],
RavenDriver,
RavenFace,
Rope USING [ROPE],
VM USING [Allocate, Interval, PageCount, PagesForWords, Pin ];
RavenDriverImpl: MONITOR
IMPORTS Basics, CountedVM, FontTune, Imager, ImagerFastShow, ImagerPixelMap, Loader, Process, PrincOpsUtils, RavenFace, VM
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, RavenFace.size[slow], RavenFace.size[fast]];
numBands: NAT = (RavenFace.size[slow]+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: RavenFace.resolution[fast], pixelUnits: TRUE, fontTuner: fontTuner];
Imager.SetPriorityImportant[context, TRUE];
Imager.RotateT[context, -90.0];
Imager.TranslateT[context, [-RavenFace.size[slow], 0]];
Imager.ScaleT[context, RavenFace.resolution[fast]/Imager.metersPerInch];
END;
lastPaperFeed: RavenFace.PaperSource ← bottom;
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
RavenFace.SetPageOffsets[
linesFromLeft: registration.short * registrationTabSize,
wordTabFromBottom: DivideUp[divident: registration.long * registrationTabSize, divisor: PrincOps.bitsPerWord]];
END; -- SetRegistration
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 [] = BEGIN ENABLE UNWIND => NULL;
UNTIL ReadyStatus[currStatus] DO
WAIT newStatus ENDLOOP;
END;
WaitPageSync: ENTRY PROC [] = BEGIN ENABLE UNWIND => NULL;
UNTIL currStatus = pageSync OR ErrorStatus[currStatus] DO
WAIT newStatus;
IF ErrorStatus[currStatus] THEN {error ← TRUE; EXIT}; ENDLOOP;
END;
WaitBand: ENTRY PROC [band: RavenFace.Index] RETURNS [BOOL] = INLINE BEGIN
ENABLE UNWIND => NULL;
WHILE RavenFace.BandFull[band] DO WAIT dataCondition^; ENDLOOP;
WHILE RavenFace.BandFull[band] DO
WAIT dataCondition^;
IF RavenFace.BandFull[band] THEN {Process.SetPriority[old]; RETURN[TRUE]};
EXIT;
ENDLOOP;
RETURN[FALSE];
END;
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
band, firstBand: RavenFace.Index; bandAddr: LONG POINTER;
totalBands: CARDINAL = pixelMap.refRep.lines/16+1;
bandsToGo: CARDINAL ← pixelMap.refRep.lines/16+1;
paperTray: RavenFace.PaperSource ← SELECT paperFeed FROM
bottom => bottom,
top => top,
alternating => IF lastPaperFeed = bottom THEN top ELSE bottom,
ENDCASE => bottom;
dstBpl: INTEGER ~ PrincOps.wordsPerPage*Basics.bitsPerWord;
printing ← TRUE;
lastPaperFeed ← paperTray;
RavenFace.WakeUp[];
WaitReady[];
IF error THEN GOTO OutErr;
[firstBand: band, firstBandAddress: bandAddr] ← RavenFace.ResetBands[];
firstBand ← band;
FOR i: CARDINAL IN [0 .. RavenFace.MaxBands-2) DO
sourceAddr: LONG POINTER ← pixelMap.refRep.pointer + Basics.LongMult[(totalBands - bandsToGo), pixelMap.refRep.rast*sizeEachBand];
bb^ ← [
dst: [word: bandAddr, bit: 0],
dstBpl: dstBpl,
src: [word: sourceAddr, bit: 0],
srcDesc: [srcBpl[pixelMap.refRep.rast*Basics.bitsPerWord]],
height: sizeEachBand,
width: pixelMap.fSize,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]
];
PrincOpsUtils.BITBLT[bb];
[nextBand: band, nextBandAddress: bandAddr] ← RavenFace.AdvanceBand[band];
bandsToGo ← bandsToGo - 1;
IF bandsToGo = 0 THEN EXIT;
ENDLOOP;
BEGIN ENABLE UNWIND => Process.SetPriority[old];
Process.SetPriority[Process.priorityFaultHandlers];
RavenFace.Feed[paperTray, aligned];
WaitPageSync[];
RavenFace.StartImage[firstBand: firstBand];
Refill bands when they have been imaged until input is exhausted
DO
sourceAddr: LONG POINTER ← pixelMap.refRep.pointer + Basics.LongMult[(totalBands - bandsToGo), pixelMap.refRep.rast*sizeEachBand];
bb^ ← [
dst: [word: bandAddr, bit: 0],
dstBpl: dstBpl,
src: [word: sourceAddr, bit: 0],
srcDesc: [srcBpl[pixelMap.refRep.rast*Basics.bitsPerWord]],
height: sizeEachBand,
width: pixelMap.fSize,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]
];
timeout ← WaitBand[band];
IF timeout THEN GOTO Out;
PrincOpsUtils.BITBLT[bb];
[nextBand: band, nextBandAddress: bandAddr] ← RavenFace.AdvanceBand[band];
bandsToGo ← bandsToGo - 1;
IF bandsToGo = 0 THEN EXIT;
ENDLOOP;
RavenFace.LastBand[band]; -- indicate that last band has been filled
timeout ← WaitBand[band];
IF timeout 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: RavenFace.PrinterStatus ← noStatus;
mySP: REF StatusProc ← NIL;
printing: BOOLFALSE;
newStatus: CONDITION;
MonitorRavenStatus: PROC [] = BEGIN
WaitStatus: ENTRY PROC [] = BEGIN ENABLE UNWIND => NULL;
ready: BOOLFALSE;
UNTIL ready DO
WAIT statusCondition^; ready ← TRUE; ENDLOOP;
END;
Note: ENTRY PROC [] = {ENABLE UNWIND => NULL; BROADCAST newStatus};
messageInternal: Message ← commandStatusFault;
Process.SetPriority[Process.priorityRealTime];
DO -- Forever
WaitStatus[];
currStatus ← RavenFace.SolicitStatus[];
IF currStatus = pageSync THEN {Note[]; LOOP};
SELECT currStatus FROM
onLine, statusOverRun, noStatus, parityError, illegalCharacter, 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, noPaper, 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,
noPaper => 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: RavenFace.PrinterStatus] RETURNS [ready: BOOL] = INLINE BEGIN
ready ← SELECT status FROM
standBy, readyToFeed => TRUE,
ENDCASE => FALSE;
END;
ErrorStatus: PROC [status: RavenFace.PrinterStatus] RETURNS [error: BOOL] = INLINE BEGIN
error ← SELECT status FROM
feederFault, registrationJam, fuserJam, noExit, interlockOpen, fuserCold, noPaper, 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};
wordsPerBand: CARDINAL = sizeEachBand * PrincOps.wordsPerPage;
sizeEachBand: CARDINAL = 16;
pagesNeedForBands: VM.PageCount = RavenFace.MaxBands * sizeEachBand + 20;
vm: VM.Interval;
activeLength: (0..PrincOps.wordsPerPage] ← (RavenFace.size[fast]+15)/16;
offset: [0..PrincOps.wordsPerPage) = PrincOps.wordsPerPage - activeLength;
statusCondition: LONG POINTER TO CONDITIONNIL; statusMask: WORD ← 0;
dataCondition: LONG POINTER TO CONDITIONNIL; dataMask: WORD ← 0;
Init: PROC [] = BEGIN
vm ← VM.Allocate[pagesNeedForBands];
RavenFace.AllocateBands[vm, RavenFace.MaxBands, sizeEachBand];
RavenFace.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]];
RavenFace.SetInterruptMasks[0, statusMask, dataMask];
RavenFace.WakeUp[]; -- Jump start the Raven
Process.Detach[FORK MonitorRavenStatus[]];
END;
ropeStatus: ARRAY RavenFace.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[illegalCharacter] ← "illegalCharacter";
ropeStatus[illegalSequence] ← "illegalSequence";
ropeStatus[noPaper] ← "Paper Tray Open or Out of Paper";
ropeStatus[pageSync] ← "pageSync";
ropeStatus[pageAtOutputTray] ← "pageAtOutputTray";
ropeStatus[tonerLow] ← "Toner Low";
ropeStatus[goingOffLine] ← "goingOffLine";
ropeStatus[offLine] ← "offLine";
ropeStatus[onLine] ← "onLine";
ropeStatus[outputTrayFull] ← "outputTrayFull";
ropeStatus[aboutToDozeOff] ← "Low Power Mode";
ropeStatus[statusError] ← "statusError";
ropeStatus[statusOverRun] ← "statusOverRun";
Init[];
END.