~ {
OPEN Dunn;
Double check abort code is working; eliminate timeouts. Cf: JamIDunn.df.
null: CHAR ~ '\000;
defaultHost: Rope.ROPE ~ "York";
time: RECORD [short, med, long: INT] ← [10, 60, 120]; -- timeouts in seconds
TOKEN: TYPE = RECORD [ok: BOOL, ch: CHAR];
NYBBLE: TYPE = MACHINE DEPENDENT RECORD [hibits: [0..17b], bit3, bit2, bit1, bit0: BOOL];
OpenFailed: PUBLIC ERROR = CODE;
InUse: PUBLIC ERROR [user: Rope.ROPE] = CODE;
SnapperError: PUBLIC ERROR [msg: Rope.ROPE] ~ CODE;
Reserve:
PUBLIC
PROC
RETURNS [handle: Handle ←
NIL, errorMsg: Rope.
ROPE ←
NIL] ~ {
open, sync, film, io : BOOL ← FALSE;
handle ← Open[!
OpenFailed => {errorMsg ← "Can't open Dunn. "; CONTINUE};
InUse => {
errorMsg ← Rope.Cat["Dunn in use by ", user.Substr[0, user.SkipTo[0, "+"]], ". "];
CONTINUE
}
];
IF errorMsg =
NIL
THEN {
[open, sync, film, io] ← Status[handle];
IF NOT open THEN errorMsg ← Rope.Concat[errorMsg, "Not opened. "];
IF NOT sync THEN errorMsg ← Rope.Concat[errorMsg, "No sync. "];
IF NOT film THEN errorMsg ← Rope.Concat[errorMsg, "No film. "];
IF NOT io THEN errorMsg ← Rope.Concat[errorMsg, "IO error. "];
};
IF errorMsg #
NIL
THEN {
IF open THEN Close[handle]; -- refuse Dunn operations
handle ← NIL;
};
};
Pretend:
PUBLIC
PROC
RETURNS [handle: Handle ←
NEW[Dunn.HandleRep]] ~ {
handle.enable ← FALSE;
};
Open:
PUBLIC
PROC [host: Rope.
ROPE ←
NIL]
RETURNS [handle: Handle] ~ {
IF host = NIL THEN host ← defaultHost;
handle ← NEW [HandleRep];
handle.enable ← TRUE;
handle.stream ← DicentraRS232CAsync.CreateStream[host: host !
IO.Error, IO.EndOfStream => ERROR OpenFailed;
DicentraRS232CAsync.CommError => ERROR OpenFailed;
DicentraRS232CAsync.CommBusy => ERROR InUse[currentUser];
];
};
HandleOK:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
RETURN[handle # NIL AND handle.stream # NIL];
};
HandleDisabled:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
RETURN[handle # NIL AND NOT handle.enable];
};
Close:
PUBLIC
PROC [handle: Handle] ~ {
IF NOT HandleOK[handle] THEN RETURN;
IO.Flush[handle.stream];
IO.Close[handle.stream --, TRUE-- ];
handle.stream ← NIL;
};
ReadToken: PROC [h: Handle, timer: INT ← time.med] RETURNS [t: TOKEN ← [TRUE, null]] ~ {
waited: BOOL ← FALSE;
FOR i: INT ← 1, i+1 DO
IF i > timer THEN {
t.ok ← FALSE;
IF waited THEN h.debug.PutF["\n"];
RETURN
};
IF IO.CharsAvail[h.stream] # 0 THEN EXIT;
IF h.debug # NIL THEN {waited ← TRUE; h.debug.PutF["wait... "]};
Process.Pause[Process.SecondsToTicks[1]];
ENDLOOP;
IF waited THEN h.debug.PutF["\n"];
t.ch ← IO.GetChar[h.stream ! IO.EndOfStream => t.ok ← FALSE];
};
Status: PUBLIC PROC [handle: Handle] RETURNS [open, sync, film, io: BOOL ← TRUE] ~ {
Check: PROC RETURNS[BOOL] ~ {
IO.PutChar[handle.stream, LOOPHOLE[cmdCode[statusRequest], CHAR]];
IO.Flush[handle.stream];
t ← ReadToken[handle, time.short]; IF NOT t.ok THEN RETURN[FALSE];
n ← LOOPHOLE[t.ch, NYBBLE];
t ← ReadToken[handle, time.short]; IF NOT t.ok THEN RETURN[FALSE];
t ← ReadToken[handle, time.short]; IF NOT t.ok THEN RETURN[FALSE];
t ← ReadToken[handle, time.short]; IF NOT t.ok OR t.ch # '\n THEN RETURN[FALSE];
RETURN[TRUE];
};
t: TOKEN;
n: NYBBLE;
IF HandleDisabled[handle] THEN RETURN;
IF NOT HandleOK[handle] THEN RETURN[open: FALSE];
THROUGH [0..10] DO
IF Check[] THEN RETURN[sync: NOT n.bit0, film: NOT n.bit3];
IO.Flush[handle.stream];
IO.Reset[handle.stream];
ENDLOOP;
RETURN[io: FALSE];
};
Cmd: PUBLIC PROC [handle: Handle, cmd: cmdCode] RETURNS [BOOL ← TRUE] ~ {
Check: PROC RETURNS[BOOL] ~ {
IO.PutChar[handle.stream, LOOPHOLE[cmdCode[readyTest], CHAR]];
IO.Flush[handle.stream];
t ← ReadToken[handle]; IF NOT t.ok OR t.ch # 'R THEN RETURN[FALSE];
t ← ReadToken[handle]; IF NOT t.ok OR t.ch # '\n THEN RETURN[FALSE];
RETURN[TRUE];
};
t: TOKEN;
IF HandleDisabled[handle] THEN RETURN;
IF NOT Ready[handle] THEN RETURN[FALSE];
IO.PutChar[handle.stream, LOOPHOLE[cmd, CHAR]]; -- send command
THROUGH [0..10] DO
IF Check[] THEN RETURN[TRUE];
IO.Flush[handle.stream];
IO.Reset[handle.stream];
ENDLOOP;
RETURN[FALSE];
};
Status:
PUBLIC
PROC [handle: Handle]
RETURNS [open, sync, film, io:
BOOL ←
TRUE] ~ {
n: NYBBLE;
IF HandleDisabled[handle] THEN RETURN;
IF NOT HandleOK[handle] THEN RETURN[open: FALSE];
IO.PutChar[handle.stream, LOOPHOLE[cmdCode[statusRequest], CHAR]];
IO.Flush[handle.stream];
n ← LOOPHOLE[IO.GetChar[handle.stream], NYBBLE];
[] ← IO.GetChar[handle.stream];
[] ← IO.GetChar[handle.stream];
IF IO.GetChar[handle.stream] # '\n THEN RETURN[io: FALSE];
RETURN[sync: NOT n.bit0, film: NOT n.bit3];
};
Ready:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
IF HandleDisabled[handle] THEN RETURN[FALSE];
IO.PutChar[handle.stream, LOOPHOLE[cmdCode[readyTest], CHAR]];
IO.Flush[handle.stream];
IF IO.GetChar[handle.stream] # 'R THEN RETURN[FALSE];
RETURN[IO.GetChar[handle.stream] = '\n];
};
Cmd:
PUBLIC
PROC [handle: Handle, cmd: cmdCode]
RETURNS [
BOOL] ~ {
IF HandleDisabled[handle] THEN RETURN[TRUE];
IF NOT Ready[handle] THEN RETURN[FALSE];
IO.PutChar[handle.stream, LOOPHOLE[cmd, CHAR]]; -- send command
RETURN[TRUE];
};
Expose:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
RETURN Cmd[handle, exposeSeq]
};
Composite:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
RETURN [Cmd[handle, selectNrmSeqMode]]
};
Separate:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
RETURN [Cmd[handle, selectSepSeqMode]]
};
Color:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
RETURN [Cmd[handle, selectColor]]
};
BW:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
RETURN [Cmd[handle, selectBW]]
};
Reset:
PUBLIC
PROC [handle: Handle]
RETURNS [
BOOL] ~ {
RETURN[
Cmd[handle, restoreFilterWheel] AND
Cmd[handle, closeAuxShutter] AND
Composite[handle] AND
Color[handle]];
};
DebugOff:
PUBLIC
PROC [handle: Handle] ~ {
IF handle # NIL THEN handle.debug ← NIL;
};
DebugOn:
PUBLIC
PROC [handle: Handle, stream:
IO.
STREAM] ~ {
IF handle # NIL THEN handle.debug ← stream;
};
Enable:
PUBLIC
PROC [handle: Handle] ~ {
IF handle # NIL THEN handle.enable ← TRUE;
};
Disable:
PUBLIC
PROC [handle: Handle] ~ {
IF handle # NIL THEN handle.enable ← FALSE;
};
colorAtom: ARRAY ImagerColorMap.Gun OF ATOM ~ [$Red, $Green, $Blue];
Snapper:
PUBLIC
PROC [action:
PROC[Imager.Context], pixelUnits:
BOOL ←
FALSE,
color: BOOL ← TRUE, smooth: BOOL ← TRUE] ~ {
err: Rope.ROPE;
handle: Dunn.Handle;
vt: Terminal.Virtual ← InterminalBackdoor.terminal;
cd: Imager.Context ~
IF smooth
OR color
THEN ColorTrixBasics.InitCd[smooth, pixelUnits, FALSE]
ELSE ColorTrixBasics.InitCd[gray, pixelUnits, FALSE];
DrawAndExpose:
PROC ~ {
saveAction: PROC ~ {action[cd]};
IF color
THEN {
IF NOT Separate[handle] THEN ERROR SnapperError["Dunn mode failure."];
FOR gun: ImagerColorMap.Gun
IN ImagerColorMap.Gun
DO
ImagerSmooth.SetComponent[cd, colorAtom[gun]];
ColorTrixBasics.ClearVt[vt, 255];
Process.CheckForAbort[];
ColorTrixMap.PrimaryOnly[gun];
Imager.DoSaveAll[cd, saveAction];
IF NOT Expose[handle] THEN ERROR SnapperError["Dunn expose failure."];
ENDLOOP;
}
ELSE {
ColorTrixBasics.ClearVt[vt, 255];
Process.CheckForAbort[];
Imager.DoSaveAll[cd, saveAction];
IF NOT Expose[handle] THEN ERROR SnapperError["Dunn expose failure."];
};
};
[handle, err] ← Reserve[];
IF err # NIL THEN ERROR SnapperError[Rope.Concat[err, "Dunn not reserved."]];
DrawAndExpose[ ! UNWIND => {Close[handle]}];
Close[handle];
};
}.