-- EikonixProtocolImpl.mesa
-- Last edited by Tim Diebert: 2-Sep-86 12:20:32
-- Copyright (C) 1985, 1986 Xerox Corporation. All rights reserved.
-- This module is based on EikonixProtocol.mesa
-- of January 27, 1986 9:21:56 am PST.
-- If it is necessary to make changes to SampleLength this code must be changed!
DIRECTORY
DicentraInputOutput USING [IOAddress, Output, RawRead, RawWrite, ReadHyper,
SetWakeupMask],
EikonixProtocol,
Environment USING [Block],
Inline USING [BITAND, BITROTATE, BITSHIFT, DBITAND, DBITSHIFT, HighByte],
Multibus USING [RawReadBlock, wordsPerBlock],
MultibusAddresses USING [scc3],
Process USING [Pause, SecondsToTicks, SetTimeout, Yield],
PupDefs USING [PupAddressLookup, PupNameTrouble],
PupStream USING [CloseReason, CreatePupByteStreamListener, PupAddress,
PupListener, RejectThisRequest, SecondsToTocks, StreamClosing],
Space USING [PagesFromWords, ScratchMap],
SpecialRuntime USING [AllocateNakedCondition],
Stream USING [Delete, GetChar, GetWord, Handle, PutBlock, PutChar, PutWord,
SendNow, TimeOut],
String USING [Copy],
Watchdog USING [Reactivate]
;
EikonixProtocolImpl: MONITOR
IMPORTS DicentraInputOutput, Inline, Multibus, Space, SpecialRuntime,
Stream, Process, PupDefs, PupStream, String, 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;
modeRegister: Address = EikonixBase + 0E00AH / 2;
resetDataInt: WORD = 2;
MyAbort: ERROR = CODE;
currentUser: LONG STRING ← [255];
dataWait: LONG POINTER TO CONDITION;
dataWaitMask: WORD;
Init: PROC [] = BEGIN
cmd: EikonixCommand ← [reg: Stage, bits: 80H]; -- Forward step.
MBWrite[deviceCommandRegister, LOOPHOLE [cmd]];
-- [dataWait, dataWaitMask] ← SpecialRuntime.AllocateNakedCondition[];
-- [] ← DicentraInputOutput.SetWakeupMask[dataWaitMask, fastThings];
-- Process.SetTimeout[dataWait, Process.SecondsToTicks[2]];
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: LOOPHOLE[EikonixProtocol.xdeScannerSocket],
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;
currentUser.length ← 0;
PupDefs.PupAddressLookup[currentUser, pupAddress
! PupDefs.PupNameTrouble =>
{String.Copy[to: currentUser, from: e]; CONTINUE}];
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[2]]; -- 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
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];
bit8: BOOL ← (Stream.GetWord[stream] = 0);
cmd: EikonixCommand ← [reg: Stage, bits: 80H];
MBWrite[deviceCommandRegister, LOOPHOLE [cmd]];
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]; -- Set the starting line.
BusyWait[]; -- and wait for it to move.
FOR i: CARDINAL IN [scanStart .. scanStart + numScans) DO
StartScan[scanBuffer, FALSE, bit8]; -- Start the scan @ i
DataWait[]; -- wait for the scan line to become ready
IF i + 1 < EikonixProtocol.Width THEN SetStagePosition[i+1];
SendMBBuffer[stream, pixelStart, numPixel, scanBuffer, bit8];
BusyWait[]; -- Wait for the stage to move.
ENDLOOP;
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
sendBuffer: Address ← dataBuffer0; scanBuffer: Address ← dataBuffer1;
tempBuffer: Address;
longCardBuffer↑ ← ALL [0];
SetStagePosition[512];
BusyWait[];
StartScan[scanBuffer, FALSE, FALSE];
SumLongCard[scanBuffer];
FOR i: CARDINAL IN [513 .. 1536) DO
p: PROCESS;
p ← FORK SumLongCard[sendBuffer];
StartScan[scanBuffer, FALSE, FALSE];
DataWait[];
SetStagePosition[i];
SumLongCard[scanBuffer];
BusyWait[];
JOIN p;
tempBuffer ← sendBuffer; sendBuffer ← scanBuffer; scanBuffer ← tempBuffer;
Watchdog.Reactivate[3*60];
IF Inline.BITAND[i, 37B] = 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;
Process.Yield[];
END;
DivideLongCardBuffer: PROC [buffer: Buffer] = BEGIN OPEN Inline;
FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO
md: MACHINE DEPENDENT RECORD [lo, hi: WORD] ←
LOOPHOLE[DBITAND[DBITSHIFT[longCardBuffer[i], - 9], 0FFFH]];
buffer.blockPointer[i] ← md.lo;
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 ← 0;
MBWrite[functionControlRegister, LOOPHOLE [funct]];
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;
DataWait: ENTRY PROC [] = BEGIN ENABLE UNWIND => NULL;
UNTIL (Inline.BITAND[MBRead[functionControlRegister], goBit]) = 0 DO
-- WAIT dataWait↑;
-- IF (Inline.BITAND[MBRead[functionControlRegister], goBit]) # 0
-- THEN BEGIN
-- MBWrite[modeRegister, resetDataInt];
-- MBWrite[modeRegister, 0];
-- ERROR MyAbort;
-- END;
-- MBWrite[modeRegister, resetDataInt];
-- MBWrite[modeRegister, 0];
-- EXIT;
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[currentUser];
END;
Init[];
END...