-- ScannerDImpl.mesa
-- Last edited by Tim Diebert: 11-Dec-85 9:21:28
-- 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],
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 ← EikonixProtocol.Width * 2,
stopIndexPlusOne: CARDINAL ← 0];
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;
FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO
buffer.blockPointer[i] ← DBITAND[DBITSHIFT[longCardBuffer[i], - 9], 0FFFH];
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...