<> <> <> <> <> 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.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: 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; <> 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 <> <> 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]; <> <> <> <> <> <> <> IF (pageBufferIndex _ pageBufferIndex + 1) > pageBufferIndexLast THEN {lastBand _ TRUE; bandLast _ band}; <> [nextBand: band, nextBandAddress: pageBufferBandBuffer] _ LSEPFace.AdvanceBand[currentBand: band]; END; -- BandCopyInternal dataOnPulses: ARRAY [0 .. 256) OF CARD _ ALL[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: BOOL _ FALSE; 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]; <> 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: BOOL _ FALSE; 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: BOOL _ FALSE; 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[]; <> 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 <> 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 CONDITION _ NIL; statusMask: WORD _ 0; dataCondition: LONG POINTER TO CONDITION _ NIL; 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[]; <> Loader.MakeProcedureResident[PrintFromPixelMap]; Loader.MakeGlobalFrameResident[PrintFromPixelMap]; [statusCondition, statusMask] _ PrincOpsUtils.AllocateNakedCondition[]; [dataCondition, dataMask] _ PrincOpsUtils.AllocateNakedCondition[]; <> 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.