-- ScannerDImpl.mesa -- Last edited by Tim Diebert: 17-Dec-85 12:26:00 -- Copyright (C) 1985, Xerox Corporation. All rights reserved. -- This module is based on EikonixProtocol.mesa of 8-Apr-85 9:25:34. -- If it is necessary to make changes to SampleLength this code must be changed! DIRECTORY DicentraInputOutput USING [IOAddress, Output, RawRead, RawWrite, ReadHyper], EikonixProtocol, Environment USING [Block, LongNumber], Inline USING [BITAND, BITROTATE, BITSHIFT, DBITAND, DBITSHIFT, HighByte], Multibus USING [RawReadBlock, wordsPerBlock], MultibusAddresses USING [scc3], Process USING [Pause, SecondsToTicks --, Yield -- ], PupStream USING [CloseReason, CreatePupByteStreamListener, PupAddress, PupListener, RejectThisRequest, SecondsToTocks, StreamClosing], Space USING [PagesFromWords, ScratchMap], Stream USING [Delete, GetChar, GetWord, Handle, PutBlock, PutChar, PutWord, SendNow, TimeOut] -- , -- Watchdog USING [Reactivate] ; ScannerDImpl: PROGRAM IMPORTS DicentraInputOutput, Inline, Multibus, Space, Stream, Process, PupStream --, Watchdog EXPORTS = BEGIN OPEN EikonixProtocol; listener: PupStream.PupListener ¬ NIL; active: BOOL ¬ FALSE; Buffer: TYPE = RECORD [blockPointer: LONG POINTER TO ARRAY [0 .. EikonixProtocol.Width) OF WORD, startIndex: CARDINAL ¬ 0, stopIndexPlusOne: CARDINAL ¬ EikonixProtocol.Width * 2]; bufferA: Buffer; bufferB: Buffer; dc: Buffer; gain: Buffer; longCardBuffer: LONG POINTER TO ARRAY [0 .. EikonixProtocol.Width) OF LONG CARDINAL; MyAbort: ERROR = CODE; Init: PROC [] = BEGIN cmd: EikonixCommand ¬ [reg: Stage, bits: 80H]; MBWrite[deviceCommandRegister, LOOPHOLE [cmd]]; active ¬ FALSE; longCardBuffer ¬ New[EikonixProtocol.Width * SIZE[LONG CARDINAL]]; bufferA.blockPointer ¬ New[EikonixProtocol.Width]; bufferB.blockPointer ¬ New[EikonixProtocol.Width]; bufferA.blockPointer­ ¬ ALL[0]; bufferA.startIndex ¬ 0; bufferA.stopIndexPlusOne ¬ EikonixProtocol.Width * 2; bufferB.blockPointer­ ¬ ALL[0]; bufferB.startIndex ¬ 0; bufferB.stopIndexPlusOne ¬ EikonixProtocol.Width * 2; dc.blockPointer ¬ New[EikonixProtocol.Width]; dc.blockPointer­ ¬ ALL[0]; dc.startIndex ¬ 0; dc.stopIndexPlusOne ¬ EikonixProtocol.Width * 2; gain.blockPointer ¬ New[EikonixProtocol.Width]; gain.blockPointer­ ¬ ALL[08000H]; -- Really 800H shifted 4 left. gain.startIndex ¬ 0; gain.stopIndexPlusOne ¬ EikonixProtocol.Width * 2; LoadIt[]; MBWrite[functionControlRegister, 0100h]; IF listener = NIL THEN listener ¬ PupStream.CreatePupByteStreamListener[ local: EikonixProtocol.scannerSocket, proc: ScannerCommand, ticks: PupStream.SecondsToTocks[30*60], filter: CheckScannerBusy]; END; ScannerCommand: PROC [stream: Stream.Handle, pupAddress: PupStream.PupAddress] = BEGIN command: EikonixProtocol.Command; BEGIN ENABLE {PupStream.StreamClosing, Stream.TimeOut, MyAbort, ABORTED => GOTO Exit}; active ¬ TRUE; DO command ¬ GetCommand[stream]; SELECT command FROM SetCommandReg => SetCommandReg[stream]; SetDeviceCommandReg => SetDeviceCommandReg[stream]; GetStatus => GetStatus[stream]; GetDeviceStatus => GetDeviceStatus[stream]; SetFCR => SetFCR[stream]; SetDMAData => SetDMAData[stream]; SendDataBuffer0 => SendDataBuffer[stream, 0]; SendDataBuffer1 => SendDataBuffer[stream, 1]; TurnOnLights => TurnOnLights[stream]; TurnOffLights => TurnOffLights[stream]; SetFilter => SetFilter[stream]; ScanPage => ScanPage[stream]; SampleScan => SampleScan[stream]; LoadNormalizer => LoadNormalizer[stream]; ScanMaxMin => ScanMaxMin[stream]; ComputeCal => ComputeCal[stream]; ENDCASE => { SendError[stream]; GOTO Exit}; Stream.SendNow[stream]; ENDLOOP; END; EXITS Exit => { Stream.Delete[stream]; KillLights[]; active ¬ FALSE; RETURN; }; END; GetCommand: PROC [stream: Stream.Handle] RETURNS [cmd: EikonixProtocol.Command] = BEGIN [] ¬ Stream.GetChar[stream]; cmd ¬ LOOPHOLE[Stream.GetChar[stream]]; RETURN[cmd]; END; SetCommandReg: PROC [stream: Stream.Handle] = BEGIN word: WORD ¬ LOOPHOLE [Stream.GetWord[stream]]; MBWrite[commandRegister, word]; EchoCommand[stream, SetCommandReg]; END; SetDeviceCommandReg: PROC [stream: Stream.Handle] = BEGIN word: WORD ¬ LOOPHOLE [Stream.GetWord[stream]]; MBWrite[deviceCommandRegister, word]; EchoCommand[stream, SetDeviceCommandReg]; END; GetStatus: PROC [stream: Stream.Handle] = BEGIN word: WORD ¬ MBRead[statusRegister]; EchoCommand[stream, GetStatus]; Stream.PutWord[stream, word]; END; GetDeviceStatus: PROC [stream: Stream.Handle] = BEGIN word: WORD ¬ MBRead[deviceCommandRegister]; EchoCommand[stream, GetDeviceStatus]; Stream.PutWord[stream, word]; END; SetFCR: PROC [stream: Stream.Handle] = BEGIN word: WORD ¬ LOOPHOLE [Stream.GetWord[stream]]; MBWrite[functionControlRegister, word]; EchoCommand[stream, SetFCR]; END; SetDMAData: PROC [stream: Stream.Handle] = BEGIN word: WORD ¬ LOOPHOLE [Stream.GetWord[stream]]; MBWrite[dataRegister, word]; EchoCommand[stream, SetDMAData]; END; SendDataBuffer: PROC [stream: Stream.Handle, buf: CARDINAL] = BEGIN a: Address ¬ IF buf = 0 THEN dataBuffer0 ELSE dataBuffer1; EchoCommand[stream, (IF buf = 0 THEN SendDataBuffer0 ELSE SendDataBuffer1)]; DicentraInputOutput.ReadHyper [to: @bufferA.blockPointer­, from: LOOPHOLE[a], words: Multibus.wordsPerBlock]; bufferA.startIndex ¬ 0; bufferA.stopIndexPlusOne ¬ Multibus.wordsPerBlock * 2; Stream.PutBlock[stream, LOOPHOLE[bufferA]]; END; TurnOnLights: PROC [stream: Stream.Handle] = BEGIN DicentraInputOutput.Output[2, LOOPHOLE [MultibusAddresses.scc3 + 5B]]; -- RTS on port 7. Process.Pause[Process.SecondsToTicks[5]]; -- Wait for the lights to come up. EchoCommand[stream, TurnOnLights]; END; TurnOffLights: PROC [stream: Stream.Handle] = BEGIN KillLights[]; EchoCommand[stream, TurnOffLights]; END; ScanPage: PROC [stream: Stream.Handle] = BEGIN useA: BOOL ¬ FALSE; first: BOOL ¬ TRUE; sendBuffer: Address ¬ dataBuffer0; scanBuffer: Address ¬ dataBuffer1; -- tempBuffer: Address; scanStart: CARDINAL ¬ Stream.GetWord[stream]; pixelStart: CARDINAL ¬ Stream.GetWord[stream]; numScans: CARDINAL ¬ Stream.GetWord[stream]; numPixel: CARDINAL ¬ Stream.GetWord[stream]; reps: CARDINAL ¬ Inline.BITAND[Stream.GetWord[stream], 17B]; bit8: BOOL ¬ (Stream.GetWord[stream] = 0); times: CARDINAL ¬ 1; cmd: EikonixCommand ¬ [reg: Stage, bits: 80H]; MBWrite[deviceCommandRegister, LOOPHOLE [cmd]]; FOR i: CARDINAL IN [1 .. reps] DO times ¬ times * 2; ENDLOOP; IF scanStart + numScans > EikonixProtocol.Height THEN SendError[stream]; IF pixelStart + numPixel > EikonixProtocol.Width THEN SendError[stream]; EchoCommand[stream, ScanPage]; Stream.PutWord[stream, numScans]; Stream.PutWord[stream, numPixel]; SetStagePosition[scanStart]; BusyWait[]; -- StartScan[scanBuffer, FALSE, bit8]; -- DataWait[]; IF times = 1 THEN BEGIN FOR i: CARDINAL IN [scanStart .. scanStart + numScans) DO -- p: PROCESS; -- IF NOT first THEN -- p ¬ FORK SendMBBuffer[stream, pixelStart, numPixel, sendBuffer, bit8]; -- StartScan[scanBuffer, TRUE, bit8]; SetStagePosition[i]; BusyWait[]; StartScan[scanBuffer, FALSE, bit8]; DataWait[]; -- SetStagePosition[i]; -- IF NOT first THEN JOIN p; -- BusyWait[]; SendMBBuffer[stream, pixelStart, numPixel, scanBuffer, bit8]; -- first ¬ FALSE; -- tempBuffer ¬ sendBuffer; sendBuffer ¬ scanBuffer; scanBuffer ¬ tempBuffer; ENDLOOP; -- SendMBBuffer[stream, pixelStart, numPixel, sendBuffer, bit8]; END ELSE BEGIN IF bit8 THEN SendError[stream]; FOR i: CARDINAL IN [scanStart .. scanStart + numScans) DO p: PROCESS; IF NOT first THEN p ¬ FORK SendBuffer[stream, pixelStart, numPixel, (IF useA THEN bufferA ELSE bufferB)]; -- Scan into ~ useA buffer FOR k: CARDINAL IN [0 .. times) DO StartScan[dataBuffer0, k = (times - 1), FALSE]; -- Watchdog.Reactivate[3*60]; BusyWait[]; SumScan[ dataBuffer0, (IF ~ useA THEN bufferA ELSE bufferB)]; ENDLOOP; IF NOT first THEN JOIN p; first ¬ FALSE; useA ¬ ~ useA; ENDLOOP; SendBuffer[stream, pixelStart, numPixel, (IF useA THEN bufferA ELSE bufferB)]; END; END; SampleScan: PROC [stream: Stream.Handle] = BEGIN sendBuffer: Address ¬ dataBuffer0; scanBuffer: Address ¬ dataBuffer1; tempBuffer: Address; cnt: CARDINAL = EikonixProtocol.Height/SampleLength; first: BOOL ¬ TRUE; bit8: BOOL ¬ Stream.GetWord[stream] = 0; EchoCommand[stream, SampleScan]; SetStagePosition[0]; BusyWait[]; StartScan[scanBuffer, FALSE, bit8]; DataWait[]; FOR i: CARDINAL IN [0 .. cnt) DO p: PROCESS; IF NOT first THEN p ¬ FORK SendSampledBuffer[stream, sendBuffer, bit8]; -- Scan into scanBuffer buffer StartScan[scanBuffer, FALSE, bit8]; DataWait[]; SetStagePosition[Inline.BITSHIFT[i, 4]]; BusyWait[]; IF NOT first THEN JOIN p; first ¬ FALSE; tempBuffer ¬ sendBuffer; sendBuffer ¬ scanBuffer; scanBuffer ¬ tempBuffer; ENDLOOP; SendSampledBuffer[stream, sendBuffer, bit8]; END; LoadNormalizer: PROC [stream: Stream.Handle] = BEGIN FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO dc.blockPointer[i] ¬ Stream.GetWord[stream]; ENDLOOP; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO gain.blockPointer[i] ¬ Stream.GetWord[stream]; ENDLOOP; LoadIt[]; EchoCommand[stream, LoadNormalizer]; END; LoadIt: PROC [] = BEGIN BusyWait[]; MBWrite[ functionControlRegister, toDarkCurrent]; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO BusyWait[]; MBWrite[dataRegister, dc.blockPointer[i]]; ENDLOOP; BusyWait[]; MBWrite[functionControlRegister, toGain]; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO BusyWait[]; MBWrite[dataRegister, gain.blockPointer[i]]; ENDLOOP; END; ScanMaxMin: PROC [stream: Stream.Handle] = BEGIN useA: BOOL ¬ FALSE; first: BOOL ¬ TRUE; sendBuffer: Address ¬ dataBuffer0; scanBuffer: Address ¬ dataBuffer1; tempBuffer: Address; minScan, minPixel: CARDINAL ¬ 0; maxScan, maxPixel: CARDINAL ¬ 0; scanStart: CARDINAL ¬ Stream.GetWord[stream]; pixelStart: CARDINAL ¬ Stream.GetWord[stream]; numScans: CARDINAL ¬ Stream.GetWord[stream]; numPixel: CARDINAL ¬ Stream.GetWord[stream]; min: CARDINAL ¬ 8000H; max: CARDINAL ¬ 0; FindMinMax: PROC [b: Address, i: CARDINAL] = BEGIN FOR j: CARDINAL IN [pixelStart .. pixelStart + numPixel) DO w: CARDINAL ¬ Inline.BITAND[MBRead[b + j], 0FFFH]; IF w < min THEN BEGIN min ¬ w; minScan ¬ i; minPixel ¬ j; END; IF w > max THEN BEGIN max ¬ w; maxScan ¬ i; maxPixel ¬ j; END; ENDLOOP; END; IF scanStart + numScans > EikonixProtocol.Height THEN SendError[stream]; IF pixelStart + numPixel > EikonixProtocol.Width THEN SendError[stream]; EchoCommand[stream, ScanMaxMin]; SetStagePosition[scanStart]; BusyWait[]; FOR i: CARDINAL IN [scanStart .. scanStart + numScans) DO p: PROCESS; IF NOT first THEN p ¬ FORK FindMinMax[sendBuffer, i - 1]; StartScan[scanBuffer, TRUE, FALSE]; DataWait[]; IF NOT first THEN JOIN p; first ¬ FALSE; tempBuffer ¬ sendBuffer; sendBuffer ¬ scanBuffer; scanBuffer ¬ tempBuffer; -- Watchdog.Reactivate[3*60]; ENDLOOP; FindMinMax[sendBuffer, scanStart + numScans - 1]; Stream.PutWord[stream, min]; Stream.PutWord[stream, minScan]; Stream.PutWord[stream, minPixel]; Stream.PutWord[stream, max]; Stream.PutWord[stream, maxScan]; Stream.PutWord[stream, maxPixel]; Stream.SendNow[stream]; END; ComputeCal: PROC [stream: Stream.Handle] = BEGIN first: BOOL ¬ TRUE; sendBuffer: Address ¬ dataBuffer0; scanBuffer: Address ¬ dataBuffer1; -- tempBuffer: Address; longCardBuffer­ ¬ ALL [0]; SetStagePosition[512]; BusyWait[]; FOR i: CARDINAL IN [512 .. 1536) DO -- p: PROCESS; -- IF NOT first THEN -- p ¬ FORK SumLongCard[sendBuffer]; -- StartScan[scanBuffer, TRUE, FALSE]; StartScan[scanBuffer, FALSE, FALSE]; DataWait[]; SumLongCard[scanBuffer]; SetStagePosition[i]; BusyWait[]; -- IF NOT first THEN JOIN p; first ¬ FALSE; -- tempBuffer ¬ sendBuffer; sendBuffer ¬ scanBuffer; scanBuffer ¬ tempBuffer; -- Watchdog.Reactivate[3*60]; IF Inline.BITAND[i, 17B] = 0 THEN Process.Pause[1]; ENDLOOP; -- SumLongCard[sendBuffer]; DivideLongCardBuffer[bufferA]; EchoCommand[stream, ComputeCal]; SendBuffer[stream, 0, EikonixProtocol.Width, bufferA]; END; cSelectClearFilter: CARDINAL = 8108H; cSelectRedFilter: CARDINAL = 8208H; cSelectGreenFilter: CARDINAL = 8308H; cSelectBlueFilter: CARDINAL = 8408H; cSelectOpaqueFilter: CARDINAL = 8508H; SetFilter: PROC [stream: Stream.Handle] = BEGIN color: Color ¬ LOOPHOLE [Stream.GetWord[stream]]; c: CARDINAL ¬ SELECT color FROM Red => cSelectRedFilter, Green => cSelectGreenFilter, Blue => cSelectBlueFilter, Opaque => cSelectOpaqueFilter, ENDCASE => cSelectClearFilter; BusyWait[]; MBWrite[deviceCommandRegister, c]; BusyWait[]; EchoCommand[stream, SetFilter]; END; SendSampledBuffer: PROC [stream: Stream.Handle, buffer: Address, bit8: BOOL] = BEGIN w: WORD; cnt: CARDINAL = EikonixProtocol.Height/SampleLength; FOR j: CARDINAL IN [0 .. cnt) DO IF bit8 THEN BEGIN w ¬ MBRead[buffer + Inline.BITSHIFT[j, 3]]; Stream.PutChar[stream, Inline.HighByte[w]]; END ELSE BEGIN w ¬ MBRead[buffer + Inline.BITSHIFT[j, 4]]; Stream.PutWord[stream, w]; END; ENDLOOP; Stream.SendNow[stream]; END; SendMBBuffer: PROC [stream: Stream.Handle, start, count: CARDINAL, ib: Address, bit8: BOOL] = BEGIN bufferA.blockPointer­ ¬ LOOPHOLE[Multibus.RawReadBlock[LOOPHOLE[ib]]]; -- DicentraInputOutput.ReadHyper -- [to: @bufferA.blockPointer­, from: LOOPHOLE[ib], words: Multibus.wordsPerBlock]; bufferA.startIndex ¬ start * (IF bit8 THEN 1 ELSE 2); bufferA.stopIndexPlusOne ¬ (start + count) * (IF bit8 THEN 1 ELSE 2); Stream.PutBlock[stream, LOOPHOLE[bufferA]]; Stream.SendNow[stream]; END; SendBuffer: PROC [stream: Stream.Handle, start, count: CARDINAL, buffer: Buffer] = BEGIN buffer.startIndex ¬ start * 2; buffer.stopIndexPlusOne ¬ (start + count) * 2; Stream.PutBlock[stream, LOOPHOLE[buffer]]; Stream.SendNow[stream]; buffer.blockPointer­ ¬ ALL [0]; END; SumScan: PROC [scanBuffer: Address, buffer: Buffer] = BEGIN FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO buffer.blockPointer[i] ¬ buffer.blockPointer[i] + Inline.BITSHIFT[ReadEikonixBuffer[scanBuffer, i], -4]; ENDLOOP; END; SumLongCard: PROC [scanBuffer: Address] = BEGIN FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO longCardBuffer[i] ¬ longCardBuffer[i] + ReadEikonixBuffer[scanBuffer, i]; ENDLOOP; END; DivideLongCardBuffer: PROC [buffer: Buffer] = BEGIN OPEN Inline; num: Environment.LongNumber; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO num ¬ LOOPHOLE[DBITAND[DBITSHIFT[longCardBuffer[i], - 10], 0FFFH]]; buffer.blockPointer[i] ¬ LOOPHOLE[num.low]; ENDLOOP; END; SetStagePosition: PROC [pos: CARDINAL] = BEGIN cmd: EikonixCommand; cmd.reg ¬ StagePosition; cmd.bits ¬ pos; MBWrite[deviceCommandRegister, LOOPHOLE [cmd]]; END; StartScan: PROC [scanBuffer: Address, step: BOOL, bit8: BOOL] = BEGIN funct: EikonixFunctionControl; IF ~ step AND ~ bit8 THEN funct.funct ¬ Data12Bit; IF ~ step AND bit8 THEN funct.funct ¬ Data8Bit; IF step AND ~ bit8 THEN funct.funct ¬ Data12Step; IF step AND bit8 THEN funct.funct ¬ Data8Step; funct.direction ¬ 1; funct.buffer ¬ IF scanBuffer = dataBuffer0 THEN 0 ELSE 1; funct.go ¬ 1; MBWrite[functionControlRegister, LOOPHOLE [funct]]; END; ReadEikonixBuffer: PROC [bufferAddress: Address, pixel: CARDINAL] RETURNS [CARDINAL] = INLINE BEGIN bufferAddress ¬ Inline.BITAND[pixel, 3777B] + bufferAddress; RETURN [MBRead[bufferAddress]]; END; SendError: PROC [stream: Stream.Handle] = BEGIN ERROR MyAbort; END; GetAddress: PROC [stream: Stream.Handle] RETURNS [EikonixProtocol.Address] = BEGIN md: MACHINE DEPENDENT RECORD [ a, b, c, d: CHAR ]; md.a ¬ Stream.GetChar[stream]; md.b ¬ Stream.GetChar[stream]; md.c ¬ Stream.GetChar[stream]; md.d ¬ Stream.GetChar[stream]; RETURN [LOOPHOLE [md]]; END; PutByteSwapWord: PROC [stream: Stream.Handle, word: WORD] = INLINE BEGIN Stream.PutWord[stream, ByteSwap[word]]; RETURN; END; ByteSwap: PROC [in: CARDINAL] RETURNS [CARDINAL] = INLINE BEGIN RETURN [LOOPHOLE[Inline.BITROTATE[in, 8]]]; END; MBWrite: PROC [reg: Address, data: WORD] = INLINE BEGIN data ¬ ByteSwap[data]; DicentraInputOutput.RawWrite[data, LOOPHOLE [reg]]; END; MBRead: PROC [reg: Address] RETURNS [WORD] = INLINE BEGIN RETURN [ByteSwap[DicentraInputOutput.RawRead[LOOPHOLE [reg]]]]; END; BusyWait: PROC [] = BEGIN UNTIL (Inline.BITAND[MBRead[statusRegister], busyBit]) = 0 DO -- Process.Yield[]; ENDLOOP; END; goBit: WORD = 1B; DataWait: PROC [] = BEGIN UNTIL (Inline.BITAND[MBRead[functionControlRegister], goBit]) = 0 DO -- Process.Yield[]; ENDLOOP; END; EchoCommand: PROC [stream: Stream.Handle, cmd: EikonixProtocol.Command] = BEGIN stream.PutChar[LOOPHOLE[200B, CHAR]]; stream.PutChar[LOOPHOLE[cmd, CHAR]]; END; KillLights: PROC [] = BEGIN DicentraInputOutput.Output[0, LOOPHOLE [MultibusAddresses.scc3 + 3B]]; DicentraInputOutput.Output[0, LOOPHOLE [MultibusAddresses.scc3 + 5B]]; END; New: PROCEDURE [words: LONG CARDINAL] RETURNS [p: LONG POINTER] = BEGIN pages: LONG CARDINAL ¬ Space.PagesFromWords[words]; p ¬ Space.ScratchMap[pages]; END; CheckScannerBusy: PROC [pupAddress: PupStream.PupAddress] = BEGIN IF active THEN ERROR PupStream.RejectThisRequest["Scanner busy"]; END; Init[]; END...