LarkControlImpl.mesa
L. Stewart, December 26, 1983 4:12 pm
Last Edited by: Swinehart, May 16, 1986 11:10:49 am PDT
DIRECTORY
Atom USING [ PutProp ],
Buttons USING [Button, ButtonProc, Create, Destroy],
ChoiceButtons USING [BuildEnumTypeSelection, BuildTextPrompt, ButtonList, PromptDataRef, SelectionNotifierProc],
Commander USING [CommandProc, Register],
CommandTool USING [NextArgument, Failed],
Containers USING [ChildXBound, ChildYBound, Create],
EditedStream USING [DeliverWhenProc],
IO,
Labels USING [Create, Label, Set],
LarkControl,
LarkPrograms USING [AddOrReplaceProgram, EnumeratePrograms, Monitor, Program, ReadProgramFromDisk],
LarkWork USING [MaybeCreateWorkArea, MaybeShutDownWorkArea],
List USING [Remove],
MBQueue USING [Create, CreateButton, Flush, Queue, QueueClientAction],
Pup USING [allNets, Address],
Rope USING [Concat, Equal, ROPE],
Rules USING [Create],
TeleLoad USING [GoToDebugger, NameToAddress, Start, StartEventServer, StartKing, Stop, StopEventServer, StopKing, teleSwatSocket],
TypeScript USING [Create],
ViewerClasses USING [Viewer],
ViewerEvents USING [EventProc, RegisterEventProc],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [OpenIcon, SetOpenHeight];
LarkControlImpl: CEDAR MONITOR
IMPORTS Atom, Buttons, ChoiceButtons, Commander, CommandTool, Containers, IO, Labels, LarkControl, LarkPrograms, LarkWork, List, MBQueue, Rope, Rules, TeleLoad, TypeScript, ViewerEvents, ViewerIO, ViewerOps
EXPORTS LarkControl =
BEGIN
The master data structure
larkControl: LIST OF REF ANYNIL;
mainSwitchRopes: ARRAY LarkControl.MainSwitchStates OF Rope.ROPE ← ["off", "manual", "auto"];
IsASPorCR: EditedStream.DeliverWhenProc = TRUSTED { RETURN [appendChar: TRUE, activate: char=' OR char = '\n]; };
GetInstanceList: PUBLIC PROC RETURNS [LIST OF REF ANY] = { RETURN [larkControl]; };
GetLogStream: PUBLIC PROC [address: Pup.Address] RETURNS [log: IO.STREAM] = {
lark: LarkControl.LarkData;
IF larkControl = NIL THEN RETURN [NIL];
IF address.net = Pup.allNets THEN RETURN [NARROW[larkControl.first, LarkControl.Data].out];
lark ← GetLark[address];
IF lark = NIL THEN RETURN [NIL];
log ← lark.h.log;
};
GetLark: PUBLIC PROC [address: Pup.Address] RETURNS [lark: LarkControl.LarkData] = {
d: LarkControl.Data;
IF larkControl = NIL THEN RETURN [NIL];
IF address.net = Pup.allNets OR address.host NOT IN LarkControl.LarkIndex THEN RETURN [NIL];
FOR ll: LIST OF REF ANY ← larkControl, ll.rest WHILE ll # NIL DO
d ← NARROW[ll.first];
IF d.net = address.net THEN RETURN[d.larks[address.host]];
ENDLOOP;
RETURN [NIL];
};
DestroyProc: ViewerEvents.EventProc = TRUSTED {
PROC [viewer: ViewerClasses.Viewer, event: ViewerEvents.ViewerEvent]
d: LarkControl.Data;
FOR ll: LIST OF REF ANY ← larkControl, ll.rest WHILE ll # NIL DO
d ← NARROW[ll.first];
IF d.viewer = viewer THEN EXIT;
REPEAT
FINISHED => d ← NIL;
ENDLOOP;
IF d # NIL THEN {
FOR i: LarkControl.LarkIndex IN LarkControl.LarkIndex DO
IF d.larks[i].eval # NIL THEN {
MBQueue.QueueClientAction[d.mbQueue, PrintBusy, d];
RETURN;
};
ENDLOOP;
larkControl ← List.Remove[ref: d, list: larkControl];
MBQueue.Flush[d.mbQueue];
MBQueue.QueueClientAction[d.mbQueue, DestroyEverything, d];
};
};
PrintBusy: PROC [clientData: REF ANY] = {
d: LarkControl.Data = NARROW[clientData];
d.out.PutRope["There are open work area.\n"];
};
Global control buttons
StopProc: Buttons.ButtonProc = TRUSTED {
d: LarkControl.Data = NARROW[clientData];
d.pleaseStop ← TRUE;
};
PrintHelp: Buttons.ButtonProc = TRUSTED {
d: LarkControl.Data = NARROW[clientData];
d.out.PutRope["See LarkControlDocumentation.tioga in Teleload.df\n"];
};
StatusAll: Buttons.ButtonProc = TRUSTED {
d: LarkControl.Data = NARROW[clientData];
lark: LarkControl.LarkData;
FOR b: LarkControl.LarkIndex IN LarkControl.LarkIndex DO
IF d.pleaseStop THEN { d.pleaseStop ← FALSE; EXIT; };
lark ← d.larks[b];
Labels.Set[lark.status, LarkControl.PollLark[lark: lark, print: shift, setPointers: mouseButton = blue]];
IF lark.event.reason # LarkControl.cDown AND lark.larkMode # 'dTHEN {
LarkControl.LarkGVSet[lark: lark, setMode: TRUE, setProgram: TRUE];
LarkControl.PaintMode[lark];
};
ENDLOOP;
};
ResetAll: Buttons.ButtonProc = TRUSTED {
d: LarkControl.Data = NARROW[clientData];
lark: LarkControl.LarkData;
FOR b: LarkControl.LarkIndex IN LarkControl.LarkIndex DO
IF d.pleaseStop THEN { d.pleaseStop ← FALSE; EXIT; };
lark ← d.larks[b];
IF lark.larkMode = 'd THEN LOOP;
IF mouseButton # yellow THEN [] ← LarkControl.SetState[h: lark.h, state: lark.state, tp: TeleLoad.GoToDebugger, print: FALSE];
IF mouseButton # red THEN LarkControl.BootLark[lark];
ENDLOOP;
};
StartAll: Buttons.ButtonProc = TRUSTED {
d: LarkControl.Data = NARROW[clientData];
lark: LarkControl.LarkData;
FOR b: LarkControl.LarkIndex IN LarkControl.LarkIndex DO
IF d.pleaseStop THEN { d.pleaseStop ← FALSE; EXIT; };
lark ← d.larks[b];
IF lark.larkMode = 'd THEN LOOP;
Labels.Set[lark.status, LarkControl.PollLark[lark: lark, print: shift, setPointers: TRUE]];
IF lark.event.reason = LarkControl.cRUNNING THEN {
LarkControl.LogEntry[lark: lark, rope: "already running\n"];
LOOP;
};
IF lark.event.reason = LarkControl.cDown THEN LOOP; -- down
LarkControl.ConsiderActionFurther[lark: lark, event: lark.event];
LarkControl.PaintMode[lark];
ENDLOOP;
};
NewSoftware: Buttons.ButtonProc = TRUSTED {
d: LarkControl.Data = NARROW[clientData];
newProgramList: LIST OF LarkPrograms.Program ← NIL;
ReParse: PROC [program: LarkPrograms.Program] RETURNS [stop: BOOL] = TRUSTED {
newProgram: LarkPrograms.Program ← LarkPrograms.ReadProgramFromDisk[objectFileName: program.programName, log: d.out, addressSpace: program.addressSpace];
IF newProgram # NIL THEN newProgramList ← CONS[newProgram, newProgramList];
RETURN [FALSE];
};
LarkPrograms.EnumeratePrograms[proc: ReParse];
WHILE newProgramList # NIL DO
LarkPrograms.AddOrReplaceProgram[newProgramList.first];
newProgramList ← newProgramList.rest;
ENDLOOP;
};
MainSwitchProc: ChoiceButtons.SelectionNotifierProc = TRUSTED {
d: LarkControl.Data = NARROW[clientdata];
FOR i: LarkControl.MainSwitchStates IN LarkControl.MainSwitchStates DO
IF Rope.Equal[name, mainSwitchRopes[i]] THEN {
d.mainSwitch ← i;
EXIT;
};
REPEAT
FINISHED => ERROR;
ENDLOOP;
};
Per-Lark control buttons
LoadThis: Buttons.ButtonProc = TRUSTED {
lark: LarkControl.LarkData = NARROW[clientData];
Labels.Set[lark.status, LarkControl.PollLark[lark: lark, print: FALSE, setPointers: TRUE]];
IF lark.event.reason = LarkControl.cRUNNING THEN {
LarkControl.LogEntry[lark: lark, rope: "already running\n"];
RETURN;
};
IF lark.program # NIL THEN lark.state ← lark.program.startState
ELSE {
LarkControl.LogEntry[lark: lark, rope: "No program selected\n"];
RETURN;
};
IF mouseButton = blue THEN LarkControl.LocalGo[lark]
ELSE {
IF lark.slaveProgram # NIL THEN LarkControl.LoadProgram[lark: lark, go: FALSE, main: FALSE];
IF lark.program # NIL THEN LarkControl.LoadProgram[lark: lark, go: shift, main: TRUE];
};
};
ResetThis: Buttons.ButtonProc = TRUSTED {
lark: LarkControl.LarkData = NARROW[clientData];
IF mouseButton # yellow THEN [] ← LarkControl.SetState[h: lark.h, state: lark.state, tp: TeleLoad.GoToDebugger, print: FALSE];
IF mouseButton # red THEN LarkControl.BootLark[lark];
};
ModeThis: Buttons.ButtonProc = TRUSTED {
lark: LarkControl.LarkData = NARROW[clientData];
IF mouseButton = red OR lark.larkMode = 'dTHEN {
lark.larkMode ← 'U;
LarkControl.LarkGVSet[lark: lark, setMode: TRUE, setProgram: TRUE];
}
ELSE lark.larkMode ← 'd;
LarkControl.PaintMode[lark];
};
DebugThis: Buttons.ButtonProc = TRUSTED {
lark: LarkControl.LarkData = NARROW[clientData];
result: Rope.ROPE;
SELECT mouseButton FROM
red => {
IF lark.eval = NIL THEN result ← LarkWork.MaybeCreateWorkArea[lark]
ELSE result ← LarkWork.MaybeShutDownWorkArea[lark];
lark.larkMode ← IF lark.eval = NIL THEN 'U ELSE 'd;
LarkControl.PaintMode[lark];
lark.world.out.PutRope[result];
};
yellow => {
LarkControl.LogEntry[lark: lark, rope: "Verify monitor", endWithCR: TRUE];
LarkControl.VerifyInternal[lark: lark, program: LarkPrograms.Monitor[log: lark.h.log, addressSpace: main], startAddress: 0E000H, stopAddress: 0];
};
blue => {
LarkControl.LogEntry[lark: lark, rope: "Verify slave EPROM", endWithCR: TRUE];
LarkControl.VerifyInternal[lark: lark, program: LarkPrograms.Monitor[log: lark.h.log, addressSpace: slave], startAddress: 0E000H, stopAddress: 0];
};
ENDCASE;
};
StatusThis: Buttons.ButtonProc = TRUSTED {
lark: LarkControl.LarkData = NARROW[clientData];
Labels.Set[lark.status, LarkControl.PollLark[lark, TRUE, mouseButton = blue]];
};
******** Viewer management ******** --
Create: Commander.CommandProc = {
arg: Rope.ROPE;
d: LarkControl.Data;
address: Pup.Address;
found: BOOL;
arg ← CommandTool.NextArgument[cmd: cmd ! CommandTool.Failed => { msg ← errorMsg; CONTINUE; }];
IF msg # NIL THEN RETURN[$Failure, msg];
IF arg = NIL THEN {
cmd.out.PutRope["Usage: LarkControl <netNumber>\n"];
RETURN;
};
[address: address, ok: found] ← TeleLoad.NameToAddress[arg.Concat["##"]];
IF NOT found THEN {
cmd.out.PutF["Net %g not found\n", IO.rope[arg]];
RETURN;
};
FOR ll: LIST OF REF ANY ← larkControl, ll.rest WHILE ll # NIL DO
d ← NARROW[ll.first];
IF d.net = address.net THEN {
cmd.out.PutF["Lark controller for net %g already exists\n", IO.rope[arg]];
RETURN;
};
ENDLOOP;
d ← NEW[LarkControl.LarkControlDataObject];
d.net ← address.net;
d.mbQueue ← MBQueue.Create[];
MBQueue.QueueClientAction[d.mbQueue, ReallyCreate, d];
};
DestroyEverything: PROC [clientData: REF ANY] = {
d: LarkControl.Data = NARROW[clientData];
lark: LarkControl.LarkData;
Turn off event server
Stop watfcher process
Stop all debug processes (or just print if there are any)
FOR i: LarkControl.LarkIndex IN LarkControl.LarkIndex DO
lark ← d.larks[i];
d.larks[i] ← NIL;
lark.world ← NIL;
TeleLoad.Stop[lark.h];
lark.h ← NIL;
lark.program ← NIL;
lark.breakList ← NIL;
lark.mode ← NIL;
lark.status ← NIL;
ENDLOOP;
TeleLoad.StopKing[];
TeleLoad.StopEventServer[];
LarkControl.StopWatcher[];
};
ReallyCreate: PROC[clientData: REF ANY] =
This is a separate procedure so that it is synchronized with d.mbQueue --
Thus, the buttons can't be invoked until we've finished creating them, and called SetWorld.
{
d: LarkControl.Data = NARROW[clientData];
v: ViewerClasses.Viewer = Containers.Create[
info: [name: IO.PutFR["Lark Control, Net %3b", IO.card[d.net]], column: left, scrollable: FALSE, iconic: TRUE]];
child: ViewerClasses.Viewer ← NIL;
x: INTEGER ← 1;
y: INTEGER ← 0;
bn: ChoiceButtons.ButtonList;
CommandButton: PROC[name: Rope.ROPE, proc: Buttons.ButtonProc, data: REF ANY,
newline: BOOL, guarded: BOOLFALSE] =
{
child ← MBQueue.CreateButton[
q: d.mbQueue,
info: [name: name, parent: v, border: TRUE, wy: y, wx: x ],
proc: proc,
clientData: data,
fork: TRUE,
paint: TRUE,
guarded: guarded];
x ← IF newline THEN 1 ELSE child.wx + child.ww - 1;
y ← IF newline THEN child.wy + child.wh - 1 ELSE child.wy;
};
LabelText: PROC[name, data: Rope.ROPE]
RETURNS[p: ChoiceButtons.PromptDataRef] =
{
p ← ChoiceButtons.BuildTextPrompt[viewer: v, x: x+1, y: y, title: name, default: data];
child ← p.promptButton;
x ← 1;
y ← child.wy + child.wh + 1;
RETURN[p]
};
Label: PROC[name: Rope.ROPE, newline: BOOL] =
{
child ← Labels.Create[
info: [name: name, parent: v, border: FALSE,
wy: y, wx: x+1],
paint: TRUE ];
x ← IF newline THEN 1 ELSE child.wx + d.maxW - 1;
y ← IF newline THEN child.wy + child.wh - 1 ELSE child.wy;
};
Rule: PROC =
{
child ← Rules.Create[
info: [parent: v, border: FALSE,
wy: y, wx: 0, ww: v.ww, wh: 1],
paint: TRUE ];
Containers.ChildXBound[v, child];
x ← 1;
y ← child.wy + child.wh + 1;
};
d.viewer ← v;
{
kludge to find max button size! --
temp: Buttons.Button = Buttons.Create[
info: [name: "ScanUniverse", parent: v, border: FALSE,
wx: 0, wy: 0],
proc: NIL, clientData: d, fork: FALSE, paint: FALSE];
d.maxW ← temp.ww;
d.buttH ← temp.wh;
Buttons.Destroy[temp];
};
bn ← LIST[mainSwitchRopes[off], mainSwitchRopes[manual], mainSwitchRopes[auto]];
d.mainSwitchController ← ChoiceButtons.BuildEnumTypeSelection[viewer: v, x: x, y: y, buttonNames: LIST[mainSwitchRopes[off], mainSwitchRopes[manual], mainSwitchRopes[auto]], default: mainSwitchRopes[off], notifyClientProc: MainSwitchProc, clientdata: d, style: menuSelection];
x ← d.mainSwitchController.nextx;
child ← Buttons.Create[info: [name: "STOP!", parent: v, border: TRUE,
wy: y, wx: x, ww: d.maxW], proc: StopProc, clientData: d];
x ← child.wx + d.maxW - 1;
new line
y ← d.mainSwitchController.nexty + 1;
x ← 1;
CommandButton[name: "Help", proc: PrintHelp, data: d, newline: FALSE];
CommandButton[name: "StatusAll", proc: StatusAll, data: d, newline: FALSE];
CommandButton[name: "ResetAll", proc: ResetAll, data: d, newline: FALSE];
CommandButton[name: "StartAll", proc: StartAll, data: d, newline: FALSE];
CommandButton[name: "NewSoftware", proc: NewSoftware, data: d, newline: TRUE];
y ← y + 3;
Rule[];
d.larksY ← y;
y ← y + (d.larksH ← 10*(d.buttH-1) + d.buttH/2);
Rule[];
d.script ← TypeScript.Create[
info: [parent: v, wh: v.ch-y, ww: v.cw,
border: FALSE,
wy: y, wx: 0] ];
Containers.ChildXBound[v, d.script];
Containers.ChildYBound[v, d.script];
d.out ← ViewerIO.CreateViewerStreams[name: NIL, viewer: d.script, editedStream: FALSE].out;
ViewerOps.SetOpenHeight[v, y + 10 * d.buttH];
CreateLarkButtons[d];
ViewerOps.OpenIcon[v];
TeleLoad.StartKing[];
TeleLoad.StartEventServer[LarkControl.NoteEvents, d];
LarkControl.StartWatcher[];
larkControl ← CONS[d, larkControl];
};
CreateLarkButtons: PROC[d: LarkControl.Data] = TRUSTED {
parent: ViewerClasses.Viewer = d.viewer;
child: ViewerClasses.Viewer ← NIL;
x: INTEGER ← 1;
y: INTEGER ← 1;
CommandButton: PROC[name: Rope.ROPE, proc: Buttons.ButtonProc, data: REF ANY,
newline: BOOL] RETURNS [ViewerClasses.Viewer] = TRUSTED {
child ← MBQueue.CreateButton[
q: d.mbQueue,
info: [name: name, parent: larkViewer, border: TRUE,
wy: y, wx: x, ww: IF newline THEN larkViewer.cw - x - 2 ELSE 0 -- d.maxW --],
proc: proc,
clientData: data,
fork: TRUE];
x ← IF newline THEN 1 ELSE child.wx + child.ww - 1;
y ← IF newline THEN child.wy + child.wh - 1 ELSE child.wy;
RETURN[child];
};
Label: PROC[name: Rope.ROPE, newline: BOOL] RETURNS [Labels.Label] = TRUSTED
{
child ← Labels.Create[ info: [name: name, parent: larkViewer, border: FALSE, wy: y, wx: x+1, ww: IF newline THEN larkViewer.cw - x - 2 ELSE 0] ];
x ← IF newline THEN 1 ELSE child.wx + child.ww - 1;
y ← IF newline THEN child.wy + child.wh - 1 ELSE child.wy;
RETURN[child];
};
larkViewer: ViewerClasses.Viewer = Containers.Create[
info: [parent: parent, border: FALSE, scrollable: TRUE,
wx: 0, wy: d.larksY, ww: parent.cw, wh: d.larksH] ];
Containers.ChildXBound[parent, larkViewer];
FOR i: LarkControl.LarkIndex IN LarkControl.LarkIndex DO
lData: LarkControl.LarkData ← NEW[LarkControl.LarkDataObject];
lData.world ← d;
lData.address.net ← d.net;
lData.address.host ← [i];
lData.address.socket ← TeleLoad.teleSwatSocket;
lData.nameRope ← lData.addressRope ← IO.PutFR["%03b#%03b#", IO.card[lData.address.net], IO.card[lData.address.host]];
[nameRope: lData.nameRope, addressRope: lData.addressRope] ← TeleLoad.AddressToName[address: lData.address];
lData.rName ← IO.PutFR["%03b#%03b#.lark", IO.card[lData.address.net], IO.card[lData.address.host]];
lData.rName ← Rope.Concat[lData.addressRope, ".lark"];
[] ← Label[IO.PutFR["%03b", IO.card[lData.address.host]], FALSE];
lData.userRNameViewer ← Label[" ", FALSE];
[] ← CommandButton["Load", LoadThis, lData, FALSE];
[] ← CommandButton["Reset", ResetThis, lData, FALSE];
lData.debug ← CommandButton["Debug", DebugThis, lData, FALSE];
lData.mode ← CommandButton["Mode W", ModeThis, lData, FALSE];
LarkControl.PaintMode[lData];
[] ← CommandButton["Status", StatusThis, lData, FALSE];
lData.status ← Label[NIL, TRUE];
Containers.ChildXBound[larkViewer, child];
lData.eval ← NIL;
lData.h ← TeleLoad.Start[host: lData.addressRope, log: lData.world.out];
IF lData.h = NIL THEN ERROR;
d.larks[i] ← lData;
ENDLOOP;
};
Mainline code. Register an event proc to handle the destruction of the viewer, then create the viewer.
[] ← ViewerEvents.RegisterEventProc[DestroyProc, destroy];
Commander.Register[key: "LarkControl", proc: Create, doc: "LarkControl net-name, Create a lark control viewer for the given network"];
Atom.PutProp[$Interfaces, $GetLogStreamProc, NEW[LarkControl.GetLogStreamProc←GetLogStream]];
END.