DIRECTORY Basics USING [BITAND, BITOR, BITSHIFT, BytePair], Eikonix, EikonixProtocol USING [BitsPerPoint, Color, Command, EikonixCommand, Height, Width, SampleLength, scannerSocket], 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], PupStream USING [Tocks, SecondsToTocks, GetPupAddress, PupNameTrouble, PupByteStreamCreate, StreamClosing, CloseReason, TimeOut], PupTypes USING [PupSocketID, PupAddress], Real USING [RoundC], Rope USING [ROPE] ; EikonixImpl: CEDAR PROGRAM IMPORTS Basics, IO, LupineRuntime, Multibus, MultibusRpcControl, Process, 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: PupTypes.PupSocketID _ EikonixProtocol.scannerSocket; ticks: PupStream.Tocks _ PupStream.SecondsToTocks[10*60]; commPortAddress: PupTypes.PupAddress _ PupStream.GetPupAddress[socket, serverName ! PupStream.PupNameTrouble => { codeRope: ROPE _ IO.PutFR[(SELECT code FROM noRoute => "No route to %g from here", noResponse => "No response from name lookup server for %g", ENDCASE => "Name %g not found"), IO.rope[serverName]]; ERROR EikonixError[ec: codeRope];}]; h _ NEW [HandleRecord]; h.serverName _ serverName; h.stream _ PupStream.PupByteStreamCreate[commPortAddress, ticks]; 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]; bytes: Basics.BytePair; cmd: EikonixProtocol.EikonixCommand; i: INTEGER _ LOOPHOLE[t]; i _ 0 - i; bytes _ LOOPHOLE[i]; cmd _ [reg: ITimeLow, bits: Basics.BITOR[bitsForLow, bytes.low]]; SetDeviceCommand[h, cmd]; cmd _ [reg: ITimeHigh, readBack: 1, bits: bytes.high]; SetDeviceCommand[h, cmd]; END; GetIntegrationTime: PUBLIC PROC[h: Eikonix.Handle] RETURNS[t: IntegrationTime] = BEGIN ENABLE PupStream.StreamClosing => MakePupStreamError [h, why, text]; cmd: EikonixProtocol.EikonixCommand _ [reg: ITimeLow, readBack: 1]; i: INTEGER; w: WORD; SetDeviceCommand[h, cmd]; w _ GetStatus[h]; UNTIL Basics.BITAND[w, 2] = 2 DO Process.Yield[]; w _ GetStatus[h]; ENDLOOP; i _ LOOPHOLE[GetDeviceStatus[h]]; i _ 0 - i; t _ LOOPHOLE[i]; 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]; buf _ IF oldBuf = NIL THEN NEW [Eikonix.NBufferRecord] ELSE oldBuf; SendCommand[h, ComputeCal]; h.stream.Flush[]; IF GetResponse[h ! PupStream.TimeOut => RETRY] # ComputeCal THEN ERROR EikonixError["Bad return command."]; FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO buf[i] _ GetWord[h ! PupStream.TimeOut => RETRY]; ENDLOOP; END; 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..... 8EikonixImpl.mesa Copyright (C) 1985, 1986, Xerox Corporation. All rights reserved. Last edited by Tim Diebert: February 10, 1986 11:35:45 am PST LineConsumerProc: TYPE ~ PROC [scanNumber: LineIndex, b: Buffer, clientData: REF ANY _ NIL] RETURNS [Buffer]; Buffer: TYPE ~ REF BufferRecord; BufferRecord: TYPE ~ RECORD [pixels: SEQUENCE cnt: CARDINAL OF BYTE12]; ELSE BEGIN FOR i: PixelCount IN [0 .. pixelCount) DO p^ _ LOOPHOLE[IO.GetChar[st], BYTE12]; p _ p + SIZE[BYTE12]; ENDLOOP; END; WriteFCR[0100h]; cmd _IF bits = bp8 THEN [reg: ITimeHigh, readBack: 1, bits: bytes.high] ELSE [reg: ITimeHigh, readBack: 0, bits: Basics.BITOR[400H, bytes.high]]; WriteFCR[0100h]; UNTIL Basics.BITAND[ReadGeneralStatus[], 8000h] = 0 DO Process.Yield[]; ENDLOOP; Buffer at this point contains the Nk' for all ks. Internal Procs ΚQ˜codešœ™K™BK™=—K˜šΟk ˜ Kš œœœœœ ˜1K˜Kšœœ\˜qKšœœ6œ˜FKšœœ˜#Kšœ œ6˜DKšœœ&˜>Kšœœ ˜Kšœ œr˜Kšœ œ˜)Kšœœ ˜Kšœœœ˜K˜—K˜šΟn œ ˜Kšœ œG˜YKšœ˜Kšœœœ˜&K˜Kšœœœ˜Kšœœœœ˜Kšœ œ ˜Kšœœ ˜K˜Kš œœœœœ˜-K˜š žœœœœœ˜HKšœ>˜DKšœ=˜=Kšœ9˜9šœQ˜Qšœ˜šœ œœœ˜+Kšœ&˜&Kšœ;˜;Kšœœ˜6—Kšœ˜$——Kšœœ˜Kšœ˜šœ ˜ Kšœ6˜6—šœ3œ ˜CKšœ œ˜*—Kšœ œ˜Kšœ˜—K˜šžœœœ˜.Kš œœœœœœ˜%Kšœ"œ˜,Kšœ+œ œ˜AKšœFœ˜PKšœ œ˜Kšœ˜—K˜šž œœœ4˜QKšœ>˜DKšœ˜Kšœ œ ˜K˜Kšœœœ%˜MKšœ˜—K˜Kšœœ˜šžœœœ4˜TKšœ>˜DKšœ˜šœœœ˜2Kšœœ˜/Kšœ˜—šœœœ˜2Kšœœ˜(Kšœ˜—K˜Kšœ˜Kšœ!œœ%˜RKšœ˜K˜—K™Kšžœœœ0œœœœ ™mKšœœœ™ Kš œœœ œœœœ™GK˜š ž œœœcœœœ˜Kšœ>˜DKšœK˜KKšœL˜Lšœœ˜Kšœœœ&˜Q—Kšœ˜Kšœ œ ˜K˜Kšœœœ%˜NKšœœœ˜>šœœœ˜&šœ˜šœ:˜šœ ˜šœœ˜.Kšœ˜Kšœœœ ˜)Kš˜—šœœœ˜.Kšœœ˜$Kšœ˜——Kšœ˜—K˜š žœœœΏœœœ˜ζKšœ>˜Dšœœ˜Kšœœœ&˜Q—Kšœœœ˜>Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ œ ˜K˜Kšœœœ%˜LKšœœœ!˜EKšœœœ"˜Gšœœœ&˜:Kšœ0˜0Kšœ$˜$Kšœ˜—Kšœ˜—K˜Kšœ œœ˜š ž œœfœœ˜Kšœœœ ˜Kš œœœœœ˜Kšœœ˜ Kš œœœœœ ˜UKšœœœ˜>Kšœ ˜ šœ ˜šœœ˜.šœ ˜ šœ˜Kšœœœ œ˜?Kšœœœ˜šœ˜Kšœ ˜ Kšœ$œ˜>—Kšœ˜Kšœ œ ˜ Kšœ ˜ —Kšœ œ˜3—KšΟc6˜6Kšœœœ˜Kš˜—šœœ˜ šœœ ˜!Kšœœ˜ šœœ˜šœ˜ Kšœœ ˜Kšœœœœ˜&Kš˜—Kšœœœ˜—Kšœœœ˜Kšœ˜—Kš œœœœœ˜2Kšœ˜—šœ™ šœœ™)Kšœœœœ™&Kšœœœ™Kšœ™—Kšœ™K™——Kšœ˜—K˜š ž œœœiœœ1œ.˜Kšœ>˜Dšœœ˜Kšœœœ&˜Q—Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœœœ%˜NK˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—K˜Kšœ˜Kšœ˜Kšœ˜šžœ œT˜xKšœ>˜DKšœ˜Kšœ$˜$Kšœœœ˜K˜ Kšœœ˜K™Kšœ#œ˜AKšœ˜Kšœ6˜6šœœ ™Kšœ0™4Kšœ,œ™I—Kšœ˜K™šœœ!™6K™Kšœ™—Kšœ˜—K˜š žœœœœ˜VKšœ>˜DKšœC˜CKšœœœ˜Kšœ˜K˜Kšœœ œ$œ˜LKšœœ˜!K˜ Kšœœ˜Kšœ˜—K˜šž œœœ˜5Kšœ>˜DKšœ˜K˜Kšœœœ%˜PKšœ˜—K˜šž œœœ˜6Kšœ>˜DKšœ˜K˜Kšœ œœ%˜QKšœ˜—K˜š ž œœœœœ˜CKšœ˜Kšœ:˜:K˜Kšœœ œ$œ˜LKšœ˜Kšœ œ˜%Kšœ˜K˜—š žœœœ œœœ˜pKšœ œ˜+Kš œœ œœœ ˜OKšœœ˜3Kšœœ˜ Kšœœ˜ Kšœœ ˜šœœ˜Kšœœœ&˜Q—Kšœ˜Kšœ˜Kšœ˜K˜Kšœ˜Kšœœ˜$Kšœ˜—K˜š žœœœ'œœ˜eKšœ>˜DKš œœ œœœœ˜CKšœ˜K˜Kšœ&œœœ%˜kšœœœ˜2Kšœ*œ˜1Kšœ˜—Kšœ˜K˜—K˜š žœœœ œœQœ˜ͺKš œœ œœœ ˜OKšœœœ œœœœ œœœ˜QKšœœ˜Kšœœ˜"Kšœœ ˜šœœ˜Kšœœœ&˜Q—Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœ˜šœœœ˜2Kšœ˜Kšœ˜—K™1K˜ šœœœ˜2Kšœœ0˜9Kšœ˜—šœœœ˜2Kšœœ˜"Kšœœœ˜8Kšœ˜Kšœ˜—Kšœ˜Kšœœ˜$Kšœ˜—K˜š ž œœœ œœ<œ˜‘Kšœ%˜%Kšœ/˜/Kšœ˜—K˜š žœœœ'œœ%˜†Kšœ œ˜Kšœ œ˜Kšœœ˜#Kšœ œ˜%Kšœ œ˜Kšœ œ ˜šœœœ ˜ Kšœœ'Ÿ˜5Kšœœ˜ Kšœ;Ÿ˜BKšœ$˜$Kšœ œœ,˜EKšœ˜Kšœ˜—Kšœ˜K˜——šΠbl™K˜K˜K˜šž œœ5˜KKšœ˜Kšœœ˜ Kšœ˜—K˜šž œœœ˜OK˜Kšœœ/˜?Kšœ˜—K˜šž œœœ˜7Kšœ>˜DKšœ˜Kšœ œ˜K˜šœ ˜&Kšœ%˜*—Kšœ˜—K˜šžœœ,˜GKšœ>˜DKšœ$˜$Kšœ œ˜K˜šœ&˜,Kšœ%˜*—Kšœ˜—K˜š ž œœœœ˜:Kšœ>˜DKšœ˜K˜Kšœœœ%˜MKšœ˜Kšœ˜—K˜š žœœœœ˜@Kšœ>˜DKšœ ˜ K˜Kšœ"œœ%˜SKšœ˜Kšœ˜—K˜šžœœœ˜3Kšœ>˜DKšœ˜Kšœ œ˜K˜šœ˜Kšœ%˜*—Kšœ˜—K˜šž œœœ˜8Kšœ>˜DKšœ˜Kšœ œ ˜K˜šœ˜#Kšœ%˜*—Kšœ˜—K˜šžœœœ˜5Kš œœ œœ œœ˜=K˜K˜Kšœ˜Kšœ˜—K˜š žœœœœ˜8Kš œœ œœ œ˜+K˜K˜Kšœœœ˜Kšœ˜K˜—K˜š žœœœœ˜@Kš œœ œœ œ˜+K˜K˜Kšœœœ˜Kšœ˜—K˜šΠbnΟbœ˜Kšœ7œ˜Dšœ œœ˜/šœœœœ˜/Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜!Kšœ ˜——Kšœ˜!Kšœ˜—K˜š žœœœœœœ˜@Kšœœ˜/Kšœ˜—K˜š žœœœœœœ˜?Kšœœ˜/Kšœ˜—K˜š žœœœœœ˜=Kšœœ˜-Kšœ˜—K˜š žœœœœœ˜