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 ];
~
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.
ROPE ←
NIL]
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: BOOL ← FALSE;
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: BOOL ← FALSE;
newStatus: CONDITION;
MonitorRavenStatus:
PROC [] =
BEGIN
WaitStatus:
ENTRY
PROC [] =
BEGIN
ENABLE
UNWIND =>
NULL;
ready: BOOL ← FALSE;
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 CONDITION ← NIL; statusMask: WORD ← 0;
dataCondition: LONG POINTER TO CONDITION ← NIL; 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[];