ScannerOpsImpl.mesa
Copyright (C) 1985, Xerox Corporation. All rights reserved.
Last edited by Tim Diebert: January 30, 1986 10:17:33 am PST
DIRECTORY
AIS USING [WriteSample, Raster, RasterPart, FRef, CreateFile, WRef, OpenWindow, CloseWindow, CloseFile],
Basics USING [BITSHIFT],
BasicTime USING [GMT, Now, Period],
Convert USING [CardFromRope, Error],
Eikonix,
EikonixProtocol USING [BitsPerPoint, Color, Height, Width, SampleLength],
FileNames USING [FileWithSearchRules],
FS USING [ComponentPositions, Error, ExpandName, StreamOpen],
IO USING [card, GetCard, Close, PutChar, PutF, PutFR, PutRope, real, rope, STREAM],
PieViewers USING [Set],
Process USING [Pause, MsecToTicks, Yield],
Rope USING [IsEmpty, ROPE],
ViewerClasses USING [Viewer],
ViewerTools USING [GetContents, SetContents],
ScannerInternal
;
ScannerOpsImpl: CEDAR MONITOR
IMPORTS AIS, Basics, BasicTime, Convert, Eikonix, FileNames, FS, IO, PieViewers, Process, Rope, ViewerTools
EXPORTS ScannerInternal
~ BEGIN
OPEN Tool: ScannerInternal;
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
bits: EikonixProtocol.BitsPerPoint ← bp8;
LoadCalFile: PUBLIC PROC [tool: Tool.Tool] = BEGIN
calFile: ROPE ← tool.scannerCalFile;
h: Eikonix.Handle;
s: STREAM;
fullPath: ROPE; ambiguous: BOOL;
it: ROPE ~ ViewerTools.GetContents[tool.iTimeViewer];
iTime: Eikonix.IntegrationTime ← 0;
iTime ← Convert.CardFromRope[it ! Convert.Error => {iTime ← 4500; CONTINUE}];
calFile ← IO.PutFR["%g-%g.txt", IO.rope[calFile], IO.card[iTime]];
[fullPath: fullPath, ambiguous: ambiguous] ← FileNames.FileWithSearchRules[root: calFile, defaultExtension: "txt", searchRules: tool.searchRules];
calFile ← fullPath;
IF Rope.IsEmpty[calFile] THEN calFile ← IO.PutFR["%g-%g.txt", IO.rope[calFile], IO.card[iTime]];
tool.out.PutF["Loading calibration from %g .. ", IO.rope[calFile]];
s ← FS.StreamOpen[calFile
! FS.Error => {tool.out.PutRope[error.explanation]; GOTO Out}];
tool.dc ← NEW [Eikonix.NBufferRecord];
tool.gain ← NEW[Eikonix.NBufferRecord];
tool.iTime ← iTime;
IF IO.GetCard[s] # iTime THEN GOTO Out;
ViewerTools.SetContents[tool.iTimeViewer, IO.PutFR["%g", IO.card[tool.iTime]]];
FOR i: CARDINAL IN Eikonix.PixelIndex DO
p: CARDINALIO.GetCard[s];
IF p # i THEN ERROR;
tool.dc[p] ← IO.GetCard[s];
tool.gain[p] ← IO.GetCard[s];
ENDLOOP;
IO.Close[s];
tool.out.PutRope[" loading normalizer .. "];
BEGIN ENABLE Eikonix.EikonixError => {tool.out.PutRope[ec]; Eikonix.Close[h]; GOTO Out};
h ← Eikonix.Open [tool.params.defaultServer];
Eikonix.LoadNormalizer[h, tool.dc, tool.gain];
Eikonix.SetIntegrationTime[h, iTime, bits];
Eikonix.SelectWheel[h, tool.color];
Eikonix.Close[h];
END;
tool.out.PutRope["Done\n"];
EXITS Out => {tool.dc ← tool.gain ← NIL; tool.out.PutRope[" Error.\n"]; RETURN;};
END;
LoadCalFile: PUBLIC PROC [tool: Tool.Tool] = BEGIN
calFile: ROPE ~ tool.scannerCalFile;
s: STREAM;
tool.out.PutF["Loading calibration from %g .. ", IO.rope[calFile]];
s ← FS.StreamOpen[calFile
! FS.Error => {tool.out.PutRope[error.explanation]; GOTO Out}];
tool.dc ← NEW [Eikonix.NBufferRecord];
tool.gain ← NEW[Eikonix.NBufferRecord];
FOR c: Tool.Color IN Tool.Color DO
tool.colorDC[c] ← NEW [Eikonix.NBufferRecord];
tool.colorGain[c] ← NEW [Eikonix.NBufferRecord];
ENDLOOP;
tool.iTime ← IO.GetCard[s];
FOR c: Tool.Color IN Tool.Color DO
tool.colorITime[c] ← IO.GetCard[s];
ENDLOOP;
ViewerTools.SetContents[tool.iTimeViewer, IO.PutFR["%g", IO.card[tool.iTime]]];
FOR i: CARDINAL IN Eikonix.PixelIndex DO
p: CARDINALIO.GetCard[s];
IF p # i THEN ERROR;
tool.dc[p] ← IO.GetCard[s];
tool.gain[p] ← IO.GetCard[s];
FOR c: Tool.Color IN Tool.Color DO
tool.colorDC[c][p] ← IO.GetCard[s];
tool.colorGain[c][p] ← IO.GetCard[s];
ENDLOOP;
ENDLOOP;
IO.Close[s];
tool.out.PutRope["Done\n"];
EXITS Out => {tool.dc ← tool.gain ← NIL; tool.out.PutRope[" Error.\n"]; RETURN;};
END;
SaveCalFile: PUBLIC PROC [tool: Tool.Tool] = BEGIN
calFile: ROPE ← tool.scannerCalFile;
cp: FS.ComponentPositions ← FS.ExpandName[calFile].cp;
s: STREAM;
wDir: ROPE ← ViewerTools.GetContents[tool.wDirViewer];
it: ROPE ~ ViewerTools.GetContents[tool.iTimeViewer];
iTime: Eikonix.IntegrationTime ← 0;
iTime ← Convert.CardFromRope[it ! Convert.Error => {iTime ← 4500; CONTINUE}];
calFile ← IO.PutFR["%g-%g.txt", IO.rope[calFile], IO.card[iTime]];
s ← FS.StreamOpen[fileName: calFile, accessOptions: create, wDir: wDir
! FS.Error => {tool.out.PutRope[error.explanation]; ERROR ABORTED}];
IO.PutF[s, "%g\n", IO.card[tool.iTime]];
IO.PutF[s, "%g %g %g %g %g\n", IO.card[tool.iTime], IO.card[tool.colorITime[Clear]], IO.card[tool.colorITime[Red]], IO.card[tool.colorITime[Green]], IO.card[tool.colorITime[Blue]]];
FOR i: CARDINAL IN Eikonix.PixelIndex DO
IO.PutF[s, "%g %g %g ", IO.card[i], IO.card[tool.dc[i]], IO.card[tool.gain[i]]];
FOR c: Tool.Color IN Tool.Color DO
IO.PutF[s, "%g %g ", IO.card[tool.colorDC[c][i]], IO.card[tool.colorGain[c][i]]];
ENDLOOP;
IO.PutChar[s, '\n];
ENDLOOP;
IO.Close[s];
END;
Calibrate: PUBLIC PROC [tool: Tool.Tool] = BEGIN OPEN Eikonix;
BEGIN
ENABLE {
UNWIND => NULL;
Eikonix.EikonixError => {tool.out.PutRope[ec]; ERROR ABORTED}};
tool.out.PutF["Calibrating at integration time: %g .. dark .. ", IO.card[tool.iTime]];
tool.dc ← CalibrateDarkCurrent[tool.params.defaultServer, tool.iTime];
tool.out.PutRope[" lights .. "];
tool.gain ← CalibrateLightsOn[server: tool.params.defaultServer, t: tool.iTime,
dc: tool.dc, color: tool.color];
tool.out.PutRope[" Done\n"];
FOR c: Tool.Color IN Tool.Color DO
tool.out.PutF["Calibrating at integration time: %g .. dark .. ", IO.card[tool.colorITime[c]]];
tool.colorDC[c] ← CalibrateDarkCurrent[tool.params.defaultServer, tool.colorITime[c]];
tool.out.PutRope[" Done\n"];
ENDLOOP;
FOR c: Tool.Color IN Tool.Color DO
tool.out.PutF["Calibrating at integration time: %g .. light .. ", IO.card[tool.colorITime[c]]];
tool.colorGain[c] ← CalibrateLightsOn[server: tool.params.defaultServer, t: tool.colorITime[c], dc: tool.colorDC[c], color: (SELECT c FROM Clear => Clear, Red => Red, Green => Green, Blue => Blue, ENDCASE => ERROR)];
tool.out.PutRope[" Done\n"];
ENDLOOP;
END; -- of begin for enable
SaveCalFile[tool];
END;
SampleScanToAisFile: PUBLIC PROC
[tool: Tool.Tool, fileName: ROPE, iTime: Eikonix.IntegrationTime] = BEGIN OPEN Eikonix;
h: Handle ← NIL;
f: AIS.FRef ← NIL;
w: AIS.WRef;
raster: AIS.Raster;
BEGIN -- THis is for the ABORTED stuff.
BEGIN
ENABLE {
UNWIND => {IF h # NIL THEN
{TurnOffLights[h ! EikonixError => CONTINUE];
Close[h ! EikonixError => CONTINUE]};
IF f # NIL THEN AIS.CloseFile[f];};
Eikonix.EikonixError => {tool.out.PutRope[ec]; ERROR ABORTED}};
proc: LineConsumerProc = BEGIN
PROC [scanNumber: LineIndex, b: Buffer, clientData: REF ANYNIL] RETURNS [Buffer];
FOR i: CARDINAL IN [0 .. b.cnt) DO
IF bits = bp8 THEN
AIS.WriteSample[w, b[i], scanNumber/EikonixProtocol.SampleLength, i]
ELSE {
sample: CARDINAL ← Basics.BITSHIFT[b[i], -4];
AIS.WriteSample[w, sample, scanNumber/EikonixProtocol.SampleLength, i]};
ENDLOOP;
ViewerTools.SetContents[tool.atScanViewer, IO.PutFR["%G", IO.card[scanNumber]]];
RETURN [b];
END;
tool.out.PutF["Opening %g .. ", IO.rope[fileName]];
raster ←
NEW[AIS.RasterPart ← [scanCount: EikonixProtocol.Width/EikonixProtocol.SampleLength,
scanLength: EikonixProtocol.Height/EikonixProtocol.SampleLength, scanMode: rd,
bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]];
f ← AIS.CreateFile[fileName, raster];
BEGIN
b: Buffer ← NEW [BufferRecord[EikonixProtocol.Width/EikonixProtocol.SampleLength]];
w ← AIS.OpenWindow[f];
h ← Open [tool.params.defaultServer];
tool.out.PutRope[" Lights .. "];
LoadNormalizer[h, tool.dc, tool.gain];
SetIntegrationTime[h, iTime, bits];
SelectWheel[h, tool.color];
TurnOnLights[h];
tool.out.PutRope[" Sample Scanning .. "];
SampleScan[h, b, proc, bits];
TurnOffLights[h];
AIS.CloseWindow[w];
AIS.CloseFile[f];
Close[h ! EikonixError => CONTINUE];
END;
END;
END;
END;
Monitor: PROC [tool: Tool.Tool, lineStart: Eikonix.LineIndex, lineCount: Eikonix.LineCount] = BEGIN
DO
scan: CARDINAL = GetScan[];
kill: BOOL = GetKill[];
num: REAL = 100.0 - (((scan - lineStart) * 100.0)/lineCount);
IF tool = NIL THEN RETURN;
IF kill THEN RETURN
ELSE ViewerTools.SetContents[tool.atScanViewer, IO.PutFR["%G", IO.card[scan]]];
PieViewers.Set[tool.pieBW, (IF num NOT IN [0.0 .. 100.0] THEN 0.0 ELSE num)];
Process.Pause[Process.MsecToTicks[1000]];
ENDLOOP;
END;
scanLine: CARDINAL ← 0;
kill: BOOLFALSE;
GetKill: ENTRY PROC [] RETURNS [BOOL] = {RETURN[kill]};
SetKill: ENTRY PROC [k: BOOL] = {kill ← k};
GetScan: ENTRY PROC [] RETURNS [CARDINAL] = {RETURN[scanLine]};
SetScan: ENTRY PROC [line: CARDINAL] = {scanLine← line};
ScanToAisFile: PUBLIC PROC [tool: Tool.Tool, fileName: ROPE, iTime: Eikonix.IntegrationTime,
color: EikonixProtocol.Color ← Clear,
lineStart: Eikonix.LineIndex ← 0, pixelStart: Eikonix.PixelIndex ← 0,
lineCount: Eikonix.LineCount ← 2048, pixelCount: Eikonix.PixelCount ← 2048] = BEGIN
OPEN Eikonix;
h: Handle ← NIL;
f: AIS.FRef ← NIL;
w: AIS.WRef;
raster: AIS.Raster;
pr: PROCESSNIL;
BEGIN -- THis is for the ABORTED stuff.
BEGIN
ENABLE {
UNWIND => TRUSTED {IF h # NIL THEN
{TurnOffLights[h ! EikonixError => CONTINUE];
Close[h ! EikonixError => CONTINUE]};
IF f # NIL THEN AIS.CloseFile[f];
SetKill[TRUE];
IF pr # NIL THEN JOIN pr;
PieViewers.Set[tool.pieBW, 0];
};
Eikonix.EikonixError => {tool.out.PutRope[ec]; ERROR ABORTED}};
proc: LineConsumerProc = BEGIN
PROC [scanNumber: LineIndex, b: Buffer, clientData: REF ANYNIL] RETURNS [Buffer];
FOR i: CARDINAL IN [0 .. pixelCount) DO
IF bits = bp8 THEN AIS.WriteSample[w, b[i], scanNumber, i]
ELSE AIS.WriteSample[w, Basics.BITSHIFT[b[i], -4], scanNumber, i];
ENDLOOP;
Process.Yield[];
SetScan[scanNumber + lineStart];
IF tool.abort THEN {tool.abort ← FALSE; ERROR ABORTED};
RETURN [b];
END;
tool.out.PutF["Opening %g .. ", IO.rope[fileName]];
PieViewers.Set[tool.pieBW, 100];
raster ←
NEW[AIS.RasterPart ← [scanCount: lineCount, scanLength: pixelCount, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]];
f ← AIS.CreateFile[fileName, raster];
SetKill[FALSE];
pr ← FORK Monitor[tool, lineStart, lineCount];
BEGIN
ndc, ngain: Eikonix.NBuffer ← NIL;
min, max: BYTE12;
b: Buffer ← NEW [BufferRecord[EikonixProtocol.Width]];
startTime: BasicTime.GMT;
c: Tool.Color ← (SELECT color FROM Clear => Clear, Red => Red, Green => Green, Blue => Blue, ENDCASE => ERROR);
w ← AIS.OpenWindow[f];
h ← Open [tool.params.defaultServer];
tool.out.PutRope[" Lights .. "];
SetIntegrationTime[h, tool.iTime, bits];
SelectWheel[h, color];
LoadNormalizer[h, tool.dc, tool.gain];
TurnOnLights[h];
IF tool.doMinMaxPreScan THEN BEGIN
tool.out.PutRope[" Computing min/max .. "];
startTime ← BasicTime.Now[];
[min: min, max: max] ← ScanForMinMax[h, lineStart, pixelStart, lineCount, pixelCount];
[ndc, ngain] ← ComputeCorrectedCalibrate[tool.dc, tool.gain, min, max];
LoadNormalizer[h, ndc, ngain];
tool.out.PutF[" %-3.2f min ..",
IO.real[BasicTime.Period[startTime, BasicTime.Now[]]/60.0]];
END;
tool.out.PutRope[" Scanning .. "];
startTime ← BasicTime.Now[];
Scan[h, lineStart, pixelStart, lineCount, pixelCount, b, proc, bits];
TurnOffLights[h];
tool.out.PutF[" %-3.2f min .. ",
IO.real[BasicTime.Period[startTime, BasicTime.Now[]]/60.0]];
IF tool.doMinMaxPreScan THEN LoadNormalizer[h, tool.dc, tool.gain];
AIS.CloseWindow[w];
AIS.CloseFile[f];
Close[h ! EikonixError => CONTINUE];
SetKill[TRUE];
TRUSTED {IF pr # NIL THEN JOIN pr};
PieViewers.Set[tool.pieBW, 0];
END;
END;
END;
END;
ReadCalibration: PUBLIC PROC
[fileName: ROPE, wDir: ROPENIL] RETURNS [dc, gain: Eikonix.NBuffer] = BEGIN
s: STREAMFS.StreamOpen[FS.ExpandName[fileName, wDir].fullFName];
dc ← NEW [Eikonix.NBufferRecord];
gain ← NEW[Eikonix.NBufferRecord];
FOR i: CARDINAL IN Eikonix.PixelIndex DO
p: CARDINALIO.GetCard[s];
IF p # i THEN ERROR;
dc[p] ← IO.GetCard[s];
gain[p] ← IO.GetCard[s];
ENDLOOP;
END;
HackCalibrate: PUBLIC PROC [] RETURNS [] = BEGIN OPEN Eikonix;
ra: REF ARRAY Eikonix.PixelIndex OF REAL;
s: STREAMFS.StreamOpen["///CalibrationDefault.txt"];
dc: Eikonix.NBuffer ← NEW[Eikonix.NBufferRecord];
gain: Eikonix.NBuffer ← NEW[Eikonix.NBufferRecord];
rawData: Eikonix.NBuffer ← NEW[Eikonix.NBufferRecord];
h: Handle ← Open ["York"];
FOR i: CARDINAL IN Eikonix.IntegrationTime DO
d[i].dc ← NEW [Eikonix.NBufferRecord ← ALL [0]];
d[i].gain ← NEW [Eikonix.NBufferRecord ← ALL [800H]];
FOR j: CARDINAL IN Eikonix.PixelIndex DO
md: MACHINE DEPENDENT RECORD [a, b: CHAR];
md.a← s.GetChar[]; md.b← s.GetChar[];
d[i].dc[j] ← LOOPHOLE [md];
md.a← s.GetChar[]; md.b← s.GetChar[];
d[i].gain[j] ← LOOPHOLE [md];
ENDLOOP;
ENDLOOP;
s.Close[];
ra ← NEW[ARRAY Eikonix.PixelIndex OF REALALL [0.0]];
FOR i: CARDINAL DECREASING IN [1 .. 11] DO
FOR j: CARDINAL IN Eikonix.PixelIndex DO
ra[j] ← ra[j] + (d[i].dc[j] - d[i-1].dc[j]);
ENDLOOP;
ENDLOOP;
FOR j: CARDINAL IN Eikonix.PixelIndex DO
ra[j] ← ra[j] / 11.0;
ENDLOOP;
s ← FS.StreamOpen["///Scanner/DarkCurrentDelta.txt", create];
FOR j: CARDINAL IN Eikonix.PixelIndex DO
IO.PutF[s, "%g %g\n", IO.card[d[0].dc[j]], IO.real[ra[j]]];
ENDLOOP;
gain^ ← ALL [0800H];
FOR i: CARDINAL IN [0 .. 4] DO
FOR j: CARDINAL IN Eikonix.PixelIndex DO
dc[j] ← LOOPHOLE[Basics.BITAND[Real.RoundC[d[0].dc[j] + (ra[j] * (i + 1))], 0FFFH]];
ENDLOOP;
LoadNormalizer[h, dc, gain];
SetIntegrationTime[h, i, bits];
SelectWheel[h, Clear];
TurnOnLights[h];
rawData ← GetCal[h];
TurnOffLights[h];
IO.PutRope[s, "\n\n"];
FOR i: CARDINAL IN [0 .. EikonixProtocol.Width) DO
IO.PutF[s, "%g %g\n", IO.card[rawData[i]], IO.card[dc[i]]];
ENDLOOP;
IO.Flush[s];
ENDLOOP;
Close[h ! EikonixError => CONTINUE];
IO.Close[s];
END;
END.