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