<> <> <> <> DIRECTORY Basics USING [BITAND, BITSHIFT, BytePair], Eikonix, EikonixProtocol USING [BitsPerPoint, Color, Command, EikonixCommand, Height, Width, SampleLength, cedarScannerSocket], IO USING [Close, GetChar, Error, Flush, PutFR, rope, PutChar, STREAM], LupineRuntime USING [BindingError], Multibus USING [Block, RawAddress, RawRead, RawReadBlock, RawWrite], MultibusRpcControl USING [ImportInterface, UnimportInterface], Process USING [Yield], Pup USING [Address, Socket], PupStream USING [Create, StreamClosing, CloseReason, -- Timeout, -- waitForever], PupName USING [Error, NameLookup], Real USING [RoundC], Rope USING [ROPE] ; EikonixImpl: CEDAR PROGRAM IMPORTS Basics, IO, LupineRuntime, Multibus, MultibusRpcControl, Process, PupName, PupStream, Real EXPORTS Eikonix ~ BEGIN OPEN Eikonix, EikonixProtocol; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; GainFactor: BYTE12 = 0800H; DefaultServer: ROPE _ "York"; EikonixError: PUBLIC ERROR [ec: ROPE] = CODE; Open: PUBLIC PROC [serverName: ROPE] RETURNS [h: Eikonix.Handle] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; socket: Pup.Socket _ LOOPHOLE[EikonixProtocol.cedarScannerSocket]; commPortAddress: Pup.Address _ PupName.NameLookup[serverName, socket ! PupName.Error => ERROR EikonixError[ec: text]]; h _ NEW [HandleRecord]; h.serverName _ serverName; h.stream _ PupStream.Create[commPortAddress, PupStream.waitForever, PupStream.waitForever]; MultibusRpcControl.ImportInterface[interfaceName: [NIL, serverName] ! LupineRuntime.BindingError => CONTINUE]; h.open _ TRUE; END; Close: PUBLIC PROC [h: Eikonix.Handle] = BEGIN IF h = NIL OR NOT h.open THEN RETURN; TurnOffLights[h ! EikonixError => CONTINUE]; h.stream.Close[ ! PupStream.StreamClosing, IO.Error => CONTINUE]; MultibusRpcControl.UnimportInterface[ ! LupineRuntime.BindingError => CONTINUE]; h.open _ FALSE; END; SelectWheel: PUBLIC PROC[h: Eikonix.Handle, color: EikonixProtocol.Color] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, SetFilter]; PutWord[h, LOOPHOLE [color]]; h.stream.Flush[]; IF GetResponse[h] # SetFilter THEN ERROR EikonixError["Bad return command."]; END; dc, g: NBuffer _ NIL; LoadNormalizer: PUBLIC PROC [h: Handle, darkCurrent: NBuffer, gain: NBuffer] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, LoadNormalizer]; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO PutWord[h, Basics.BITSHIFT[darkCurrent[i], 4]]; ENDLOOP; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO PutWord[h, Basics.BITSHIFT[gain[i], 4]]; ENDLOOP; h.stream.Flush[]; dc _ darkCurrent; g _ gain; IF GetResponse[h] # LoadNormalizer THEN ERROR EikonixError["Bad return command."]; END; <<>> <> <> <> SampleScan: PUBLIC PROC [h: Handle, b: Buffer, p: LineConsumerProc, bits: EikonixProtocol.BitsPerPoint _ bp8, clientData: REF ANY _ NIL] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; scanCount: LineCount ~ EikonixProtocol.Height/EikonixProtocol.SampleLength; pixelCount: PixelCount ~ EikonixProtocol.Width/EikonixProtocol.SampleLength; IF NOT CheckOnLine[h] THEN {Close[h ! EikonixError => CONTINUE]; ERROR EikonixError["Scanner not online."]}; SendCommand[h, SampleScan]; PutWord[h, LOOPHOLE [bits]]; h.stream.Flush[]; IF GetResponse[h] # SampleScan THEN ERROR EikonixError["Bad return command."]; IF b.cnt < pixelCount THEN b _ NEW [BufferRecord[pixelCount]]; FOR i: CARDINAL IN [0 .. scanCount) DO pix: LineIndex _ IF i * EikonixProtocol.SampleLength < EikonixProtocol.Height THEN i * EikonixProtocol.SampleLength ELSE EikonixProtocol.Height - 1; CollectSampleLine[h, b, pixelCount, bits]; b _ p[pix, b, clientData]; ENDLOOP; END; CollectSampleLine: PROC [h: Handle, b: Buffer, pixelCount: PixelCount, bits: EikonixProtocol.BitsPerPoint _ bp8] = BEGIN w: WORD; IF b.cnt < pixelCount THEN b _ NEW [BufferRecord[pixelCount]]; IF bits = bp12 THEN FOR i: PixelCount IN [0 .. pixelCount) DO w _ GetWord[h]; b[i] _ LOOPHOLE[Basics.BITAND[w, 0FFFH]]; ENDLOOP ELSE FOR i: PixelCount IN [0 .. pixelCount) DO b[i] _ LOOPHOLE[h.stream.GetChar[]]; ENDLOOP; END; Scan: PUBLIC PROC [h: Handle, lineStart: LineIndex, pixelStart: PixelIndex, lineCount: LineCount, pixelCount: PixelCount, b: Buffer, p: LineConsumerProc, bits: EikonixProtocol.BitsPerPoint _ bp8, clientData: REF ANY _ NIL] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; IF NOT CheckOnLine[h] THEN {Close[h ! EikonixError => CONTINUE]; ERROR EikonixError["Scanner not online."]}; IF b.cnt < pixelCount THEN b _ NEW [BufferRecord[pixelCount]]; SendCommand[h, ScanPage]; PutWord[h, lineStart]; PutWord[h, pixelStart]; PutWord[h, lineCount]; PutWord[h, pixelCount]; PutWord[h, LOOPHOLE [bits]]; h.stream.Flush[]; IF GetResponse[h] # ScanPage THEN ERROR EikonixError["Bad return command."]; IF lineCount # GetWord[h] THEN ERROR EikonixError["Bad line count."]; IF pixelCount # GetWord[h] THEN ERROR EikonixError["Bad pixel count."]; FOR i: CARDINAL IN [lineStart .. lineStart + lineCount) DO CollectLine[h, b, pixelCount, bits, pixelStart]; b _ p[i - lineStart, b, clientData]; ENDLOOP; END; normalize: BOOL _ FALSE; CollectLine: PROC [h: Handle, b: Buffer, pixelCount: PixelCount, bits: EikonixProtocol.BitsPerPoint _ bp8, pixelStart: CARDINAL] = TRUSTED BEGIN st: IO.STREAM = h.stream; p: LONG POINTER TO BYTE12; odd: BOOL; pc: PixelCount _ IF (odd _ pixelCount MOD 2 # 0) THEN pixelCount - 1 ELSE pixelCount; IF b.cnt < pixelCount THEN b _ NEW [BufferRecord[pixelCount]]; p _ @b[0]; IF bits = bp12 THEN FOR i: PixelCount IN [0 .. pixelCount) DO IF normalize THEN { buf: LONG CARDINAL _ Basics.BITAND [GetByteSwapWord[h], 0FFFH]; buf2: LONG CARDINAL; IF buf < dc[i+pixelStart] THEN buf2 _ 0 ELSE buf2 _ (buf - dc[i+pixelStart]) * LONG[g[i+pixelStart]]; buf2 _ buf2/2048; IF buf2 > 4095 THEN buf2 _ 4095; p^ _ buf2} ELSE p^ _ Basics.BITAND[GetByteSwapWord[h], 0FFFH]; -- I am not sure why but the data is always in lo pos. p _ p + SIZE[BYTE12]; ENDLOOP ELSE BEGIN FOR i: PixelCount IN [0 .. pc) DO ch: CHAR; IF i MOD 2 = 0 THEN BEGIN ch _ IO.GetChar[st]; p^ _ LOOPHOLE[IO.GetChar[st], BYTE12]; END ELSE p^ _ LOOPHOLE[ch, BYTE12]; p _ p + SIZE[BYTE12]; ENDLOOP; IF odd THEN p^ _ LOOPHOLE[IO.GetChar[st], BYTE12]; END; <> <> <> <

> <> <> <<>> END; ScanForMinMax: PUBLIC PROC [h: Handle, lineStart: LineIndex, pixelStart: PixelIndex, lineCount: LineCount, pixelCount: PixelCount] RETURNS [min: BYTE12, minScan: LineIndex, minPixel: PixelIndex, max: BYTE12, maxScan: LineIndex, maxPixel: PixelIndex] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; IF NOT CheckOnLine[h] THEN {Close[h ! EikonixError => CONTINUE]; ERROR EikonixError["Scanner not online."]}; SendCommand[h, ScanMaxMin]; PutWord[h, lineStart]; PutWord[h, pixelStart]; PutWord[h, lineCount]; PutWord[h, pixelCount]; h.stream.Flush[]; IF GetResponse[h] # ScanMaxMin THEN ERROR EikonixError["Bad return command."]; min _ GetWord[h]; minScan _ GetWord[h]; minPixel _ GetWord[h]; max _ GetWord[h]; maxScan _ GetWord[h]; maxPixel _ GetWord[h]; END; bitsForLow: [0..0FFFh] _ 500H; bitsForHi: [0..0FFFh] _ 000H; reBit: [0..1] _ 1; SetIntegrationTime: PUBLIC PROC[h: Eikonix.Handle, t: IntegrationTime, bits: EikonixProtocol.BitsPerPoint _ bp8] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> END; GetIntegrationTime: PUBLIC PROC[h: Eikonix.Handle] RETURNS[t: IntegrationTime] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; <> <> <> <> <> <> <> <> END; TurnOnLights: PUBLIC PROC [h: Eikonix.Handle] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, TurnOnLights]; h.stream.Flush[]; IF GetResponse[h] # TurnOnLights THEN ERROR EikonixError["Bad return command."]; END; TurnOffLights: PUBLIC PROC [h: Eikonix.Handle] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, TurnOffLights]; h.stream.Flush[]; IF GetResponse[h] # TurnOffLights THEN ERROR EikonixError["Bad return command."]; END; CheckOnLine: PUBLIC PROC [h: Eikonix.Handle] RETURNS [BOOL] = BEGIN w: WORD; SetDeviceCommand[h, [reg: Console, readBack: 1, bits: 0]]; w _ GetStatus[h]; UNTIL Basics.BITAND[w, 2] = 2 DO Process.Yield[]; w _ GetStatus[h]; ENDLOOP; w _ GetDeviceStatus[h]; RETURN [Basics.BITAND[w, 20H] = 20H]; END; CalibrateDarkCurrent: PUBLIC PROC [server: ROPE _ NIL, t: IntegrationTime] RETURNS [dc: Eikonix.NBuffer] = BEGIN dcScans: CARDINAL = EikonixProtocol.Height; h: Handle _ Open [(IF server = NIL THEN (server _ DefaultServer) ELSE server)]; gain: Eikonix.NBuffer _ NEW[Eikonix.NBufferRecord]; dc _ NEW[Eikonix.NBufferRecord]; dc^ _ ALL[0]; gain^ _ ALL[GainFactor]; IF NOT CheckOnLine[h] THEN {Close[h ! EikonixError => CONTINUE]; ERROR EikonixError["Scanner not online."]}; SelectWheel[h, Opaque]; SetIntegrationTime[h, t]; LoadNormalizer[h, dc, gain]; dc _ GetCal[h, dc]; LoadNormalizer[h, dc, gain]; Close[h ! EikonixError => CONTINUE]; END; GetCal: PUBLIC PROC [h: Handle, oldBuf: Eikonix.NBuffer _ NIL] RETURNS [buf: Eikonix.NBuffer] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; b: Buffer _ NEW [BufferRecord[EikonixProtocol.Width]]; array: REF ARRAY [0 .. 2048) OF INT _ NEW[ARRAY [0 .. 2048) OF INT]; proc: LineConsumerProc = BEGIN <> FOR i: CARDINAL IN [0 .. 2048) DO array^[i] _ array^[i] + b[i]; ENDLOOP; Process.Yield[]; RETURN [b]; END; array^ _ ALL[0]; buf _ IF oldBuf = NIL THEN NEW [Eikonix.NBufferRecord] ELSE oldBuf; Scan[h, 512, 0, 1024, 2048, b, proc, bp12]; FOR i: CARDINAL IN [0 .. 2048) DO buf[i] _ array[i] / 1024; ENDLOOP; END; <> < MakePupStreamError [h, why, text];>> <> <> <> < RETRY] # ComputeCal THEN ERROR EikonixError["Bad return command."];>> <> < RETRY];>> <> <> <<>> CalibrateLightsOn: PUBLIC PROC [server: ROPE _ NIL, t: IntegrationTime, color: EikonixProtocol.Color _ Clear, dc: Eikonix.NBuffer] RETURNS [gain: Eikonix.NBuffer] = BEGIN h: Handle _ Open [(IF server = NIL THEN (server _ DefaultServer) ELSE server)]; buffer: REF ARRAY PixelIndex OF REAL _ NEW [ARRAY PixelIndex OF REAL _ ALL[0.0]]; max: REAL _ 0.0; gain _ NEW[Eikonix.NBufferRecord]; gain^ _ ALL[GainFactor]; IF NOT CheckOnLine[h] THEN {Close[h ! EikonixError => CONTINUE]; ERROR EikonixError["Scanner not online."]}; LoadNormalizer[h, dc, gain]; SelectWheel[h, color]; SetIntegrationTime[h, t]; TurnOnLights[h]; gain _ GetCal[h, gain]; TurnOffLights[h]; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO buffer[i] _ gain[i]; ENDLOOP; <> max _ 0.0; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO max _ MAX [max, (4095.0 * (buffer[i]/(4095.0 - dc[i])))]; ENDLOOP; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO mumble: REAL _ max/buffer[i]*800H; IF mumble < 0.0 OR mumble > 4095.0 THEN mumble _ 4095.0; gain[i] _ Real.RoundC[mumble]; ENDLOOP; LoadNormalizer[h, dc, gain]; Close[h ! EikonixError => CONTINUE]; END; Calibrate: PUBLIC PROC [server: ROPE _ NIL, t: IntegrationTime, color: EikonixProtocol.Color _ Clear] RETURNS [dc, gain: Eikonix.NBuffer] = BEGIN dc _ CalibrateDarkCurrent[server, t]; gain _ CalibrateLightsOn[server, t, color, dc]; END; ComputeCorrectedCalibrate: PUBLIC PROC [dc, gain: Eikonix.NBuffer, min, max: BYTE12] RETURNS [newDc, newGain: Eikonix.NBuffer] = BEGIN minReal: REAL _ min; maxReal: REAL _ max; newDc _ NEW[Eikonix.NBufferRecord]; newGain _ NEW[Eikonix.NBufferRecord]; newDc^ _ ALL[0]; newGain^ _ ALL[GainFactor]; FOR i: CARDINAL IN PixelIndex DO v: REAL _ maxReal/(gain[i]/2048.0) + dc[i]; -- 800H ir: REAL; newDc[i] _ Real.RoundC[minReal/(gain[i]/2048.0) + dc[i]]; -- 800H ir _ (4095.0/(v - newDc[i])) * 800H; IF ir > 4095.0 THEN ERROR EikonixError["Gain greater than 2 needed"]; newGain[i] _ Real.RoundC[ir]; ENDLOOP; END; <> SendCommand: PROC [h: Eikonix.Handle, cmd: EikonixProtocol.Command] = BEGIN h.stream.PutChar['\000]; h.stream.PutChar[LOOPHOLE[cmd]]; END; GetResponse: PROC [h: Eikonix.Handle] RETURNS [EikonixProtocol.Command] = BEGIN [] _ h.stream.GetChar[]; RETURN [LOOPHOLE[h.stream.GetChar[], EikonixProtocol.Command]]; END; SetCommand: PROC [h: Eikonix.Handle, cmd: WORD] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, SetCommandReg]; PutWord[h, LOOPHOLE [cmd]]; h.stream.Flush[]; IF GetResponse[h] # SetCommandReg THEN ERROR EikonixError["Bad return command."]; END; SetDeviceCommand: PROC [h: Eikonix.Handle, cmd: EikonixCommand] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, SetDeviceCommandReg]; PutWord[h, LOOPHOLE [cmd]]; h.stream.Flush[]; IF GetResponse[h] # SetDeviceCommandReg THEN ERROR EikonixError["Bad return command."]; END; GetStatus: PROC [h: Eikonix.Handle] RETURNS [WORD] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, GetStatus]; h.stream.Flush[]; IF GetResponse[h] # GetStatus THEN ERROR EikonixError["Bad return command."]; RETURN [GetWord[h]]; END; GetDeviceStatus: PROC [h: Eikonix.Handle] RETURNS [WORD] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, GetDeviceStatus]; h.stream.Flush[]; IF GetResponse[h] # GetDeviceStatus THEN ERROR EikonixError["Bad return command."]; RETURN [GetWord[h]]; END; SetFCR: PROC [h: Eikonix.Handle, cmd: WORD] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, SetFCR]; PutWord[h, LOOPHOLE [cmd]]; h.stream.Flush[]; IF GetResponse[h] # SetFCR THEN ERROR EikonixError["Bad return command."]; END; SetDMAData: PROC [h: Eikonix.Handle, word: WORD] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; SendCommand[h, SetDMAData]; PutWord[h, LOOPHOLE [word]]; h.stream.Flush[]; IF GetResponse[h] # SetDMAData THEN ERROR EikonixError["Bad return command."]; END; PutWord: PROC [h: Eikonix.Handle, word: WORD] = BEGIN md: MACHINE DEPENDENT RECORD [ a, b: CHAR] _ LOOPHOLE [word]; h.stream.PutChar[md.a]; h.stream.PutChar[md.b]; RETURN; END; GetWord: PROC [h: Eikonix.Handle] RETURNS [WORD] = BEGIN md: MACHINE DEPENDENT RECORD [ a, b: CHAR]; md.a _ h.stream.GetChar[]; md.b _ h.stream.GetChar[]; RETURN [LOOPHOLE[md, WORD]]; END; GetByteSwapWord: PROC [h: Eikonix.Handle] RETURNS [WORD] = BEGIN md: MACHINE DEPENDENT RECORD [ a, b: CHAR]; md.b _ h.stream.GetChar[]; md.a _ h.stream.GetChar[]; RETURN [LOOPHOLE[md, WORD]]; END; MakePupStreamError: PROC [ h: Eikonix.Handle, why: PupStream.CloseReason, text: ROPE] = BEGIN codeRope: ROPE _ IO.PutFR["Error from %g; %s ", IO.rope[h.serverName], IO.rope[SELECT why FROM localClose => "Local Close", localAbort => "Local Abort", remoteClose => "Remote Close", noRouteToNetwork => "No route", transmissionTimeout => "Timeout", ENDCASE => text]]; ERROR EikonixError[ec: codeRope]; END; ReadGeneralStatus: PUBLIC PROC [] RETURNS [WORD] = TRUSTED BEGIN RETURN [Read[LOOPHOLE[0400000H+(0E004H / 2)]]]; END; ReadDeviceStatus: PUBLIC PROC [] RETURNS [WORD] = TRUSTED BEGIN RETURN [Read[LOOPHOLE[0400000H+(0E006H / 2)]]]; END; WriteGeneralCommand: PUBLIC PROC [word: WORD] = TRUSTED BEGIN Write[LOOPHOLE[0400000H+(0E000H / 2)], word]; END; WriteDeviceCommand: PUBLIC PROC [word: WORD] = TRUSTED BEGIN Write[LOOPHOLE[0400000H+(0E002H / 2)], word]; END; WriteFCR: PUBLIC PROC [word: WORD] = TRUSTED BEGIN Write[LOOPHOLE[0400000H+(0E00EH / 2)], word]; END; Read: PUBLIC PROC [add: Multibus.RawAddress] RETURNS [word: WORD] = TRUSTED BEGIN foo: Basics.BytePair _ Multibus.RawRead[add]; bar: Basics.BytePair; bar.high _ foo.low; bar.low _ foo.high; RETURN [LOOPHOLE[bar]]; END; LineRec: TYPE ~ RECORD[SEQUENCE cnt: CARDINAL OF WORD]; ReadBuffer: PUBLIC PROC [add: Multibus.RawAddress] RETURNS [w: REF LineRec] = TRUSTED BEGIN block: Multibus.Block _ Multibus.RawReadBlock[add]; w _ NEW[LineRec[2048]]; FOR i: CARDINAL IN [0 .. 2048) DO foo: Basics.BytePair _ LOOPHOLE[block[i]]; bar: Basics.BytePair; bar.high _ foo.low; bar.low _ foo.high; w[i] _ LOOPHOLE[bar]; ENDLOOP; END; Write: PUBLIC PROC [add: Multibus.RawAddress, word: WORD] = TRUSTED BEGIN foo: Basics.BytePair _ LOOPHOLE[word]; bar: Basics.BytePair; bar.high _ foo.low; bar.low _ foo.high; Multibus.RawWrite[bar, add]; END; END.....