IMSLinkImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Gasbarro March 11, 1986 3:17:09 pm PST
DIRECTORY
Ascii, Commander, EditedStream, GPIB, IO, Menus, Process, RefText, Rope, TypeScript, ViewerClasses, ViewerIO, ViewerOps, ViewerTools;
IMSLinkImpl:
CEDAR
PROGRAM
IMPORTS Commander, EditedStream, GPIB, IO, Menus, Process, RefText, Rope, TypeScript, ViewerIO, ViewerOps, ViewerTools
= BEGIN
DisconnectChar: CHAR = 220C;
ConnectChar: CHAR = 222C;
Handle: TYPE = REF IMSCommandInstanceRecord;
IMSCommandInstanceRecord:
TYPE =
RECORD [
ts: TypeScript.TS, -- the primary typescript
ControllerToDeviceProcess: PROCESS,
connectionOpen: BOOL ← FALSE,
prompt: Rope.ROPE ← "IM$",
in: IO.STREAM,
out: IO.STREAM,
addr: GPIB.DeviceAddr ← 1 -- default address
];
sendBuffer: REF TEXT ← RefText.New[GPIB.maxWriteBuffer];
recvBuffer: Rope.ROPE;
OpenConnection:
PROC [h: Handle] =
TRUSTED {
ViewerTools.SetSelection[h.ts, NIL];
h.out.PutF["Opening connection to IMS... "];
IF
GPIB.InitializeController[]
THEN {
GPIB.InterfaceClear[];
GPIB.SelectedDeviceClear[h.addr];
h.out.PutF["open.\n"];
h.connectionOpen ← TRUE;
PutPrompt[h];
} ELSE {h.out.PutF["\nUnable to initialize GPIB.\n"]; h.connectionOpen ← FALSE};
};
CloseConnection:
PROC [h: Handle, print:
BOOL] =
TRUSTED {
IF h.connectionOpen
THEN {
h.out.PutF["\nClosing connection to IMS..."];
GPIB.FinalizeController[];
h.out.PutF["Closed.\n"];
};
h.connectionOpen ← FALSE;
};
PutPrompt:
PROC [h: Handle] = {
h.out.PutF["%l%g:%l ", IO.rope["b"], IO.rope[h.prompt], IO.rope["B"]];
sendBuffer.length ← 0;
};
ControllerToDevice:
PROC [h: Handle] =
TRUSTED {
-- watches keyboard & viewer buttons
char: CHAR;
oldSendBufferLength: NAT ← 0;
waitingForEnd: BOOL ← FALSE;
sendBuffer.length ← 0;
DO
ENABLE
ABORTED, IO.Error =>
GOTO die;
--viewer was destroyed or STOP! pushed
char ← h.in.GetChar[];
IF char=ConnectChar AND NOT h.connectionOpen THEN {OpenConnection[h]; LOOP};
IF h.connectionOpen
THEN
SELECT char
FROM
DisconnectChar => CloseConnection[h, TRUE];
Ascii.
BS, Ascii.
DEL, '\001 => {
IF sendBuffer.length = 0
THEN
LOOP;
--avoid smashing prompt
TypeScript.BackSpace[h.ts];
sendBuffer.length ← sendBuffer.length-1};
Ascii.
ESC =>
IF sendBuffer.length=0
THEN {
sendBuffer.length ← oldSendBufferLength-1; --strip the '\l
FOR i:
NAT
IN [0..sendBuffer.length)
DO
h.out.PutChar[sendBuffer[i]];
ENDLOOP;
}
ELSE {
h.out.PutChar[char];
sendBuffer ← RefText.AppendChar[sendBuffer, char];
};
Ascii.
CR => {
sendRope: Rope.ROPE;
h.out.PutChar[char];
sendBuffer ← RefText.AppendChar[sendBuffer, '\l];
--IMS terminator
handle a multi-line commands, ship each line out asap to avoid buffer o/flow
sendRope ← Rope.FromRefText[sendBuffer];
IF Rope.Match["*DIAG*", sendRope, FALSE] THEN h.prompt ← "IMS Diag";
IF Rope.Match["*END*", sendRope, FALSE] THEN h.prompt ← "IM$";
IF Rope.Match["*#TXT*", sendRope, FALSE] THEN waitingForEnd ← TRUE;
IF waitingForEnd AND Rope.Match["*END*", Rope.FromRefText[sendBuffer], FALSE] THEN waitingForEnd ← FALSE;
GPIB.WriteDevice[h.addr, Rope.FromRefText[sendBuffer]];
oldSendBufferLength ← sendBuffer.length;
sendBuffer.length ← 0;
IF
NOT waitingForEnd
THEN {
GetResponse[h];
PutPrompt[h]
};
};
ENDCASE => {
h.out.PutChar[char];
sendBuffer ← RefText.AppendChar[sendBuffer, char];
};
ENDLOOP;
EXITS
die => {GPIB.FinalizeController[]; h.connectionOpen ← FALSE};
};
GetResponse:
PROC [h: Handle] = {
c: CHAR;
TRUSTED {recvBuffer ← GPIB.ReadDevice[h.addr]};
IF Rope.Match["End", recvBuffer]
THEN h.out.PutF["%g\n",
IO.rope[recvBuffer]]
ELSE {
FOR i: INT IN [0..Rope.Length[recvBuffer]) DO
c ← Rope.Fetch[recvBuffer, i];
IF c = '\l THEN LOOP;
SELECT c
FROM
Ascii.BEL => NULL;
Ascii.ControlA, Ascii.BS => TypeScript.BackSpace[h.ts];
Ascii.TAB, Ascii.CR, IN[Ascii.SP..0176C] => h.out.PutChar[c];
ENDCASE => NULL;
ENDLOOP;
};
EXITS
};
IMSLinkMain: Commander.CommandProc =
TRUSTED {
h: Handle ← NEW[IMSCommandInstanceRecord ← []];
h.ts ← TypeScript.Create[info: [name: "IMS Link", iconic: FALSE], paint: TRUE];
TypeScript.ChangeLooks[h.ts, 'f]; -- look fixed pitch Gacha
[h.in, h.out] ← ViewerIO.CreateViewerStreams[name: "IMSCommander.log", viewer: h.ts, editedStream: FALSE];
EditedStream.SetEcho[h.in, NIL];
Menus.AppendMenuEntry[menu: h.ts.menu, entry: Menus.CreateEntry[name: "Disconnect", proc: MyDisconnect, clientData: h, fork: TRUE, documentation: "Close GPIB connection"]];
Menus.AppendMenuEntry[menu: h.ts.menu, entry: Menus.CreateEntry[name: "Connect", proc: MyConnect, clientData: h, documentation: "Open GPIB Connection to selected host"]];
Menus.AppendMenuEntry[menu: h.ts.menu, entry: Menus.CreateEntry[name: "STOP!", proc: MyStop, clientData: h, fork: TRUE, documentation: "Stop everything!"]];
ViewerOps.PaintViewer[viewer: h.ts, hint: all];
h.ControllerToDeviceProcess ← FORK ControllerToDevice[h];
Process.Detach[h.ControllerToDeviceProcess];
};
MyConnect: Menus.MenuProc = {
viewer: TypeScript.TS ← NARROW[parent];
h: Handle ← NARROW[clientData];
h.ts ← viewer; -- "primary" copy
TypeScript.InsertCharAtFrontOfBuffer[ts: h.ts, char: ConnectChar];
};
MyDisconnect: Menus.MenuProc = {
h: Handle ← NARROW[clientData];
TypeScript.InsertCharAtFrontOfBuffer[ts: h.ts, char: DisconnectChar];
};
MyStop: Menus.MenuProc =
TRUSTED {
h: Handle ← NARROW[clientData];
Process.Abort[h.ControllerToDeviceProcess ! Process.InvalidProcess => CONTINUE];
};
Init:
PROC = {
Commander.Register[key: "IMSLink", proc: IMSLinkMain, doc: "\n\n\tSimple command interface to IMS Logic Master 1000. \n", interpreted: FALSE];
};
Init[];
END.