-- 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...