LarkSmartsSupImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Last modified by D. Swinehart, May 17, 1986 4:14:59 pm PDT
Polle Zellweger (PTZ) August 27, 1985 9:07:50 pm PDT
DIRECTORY
Commander USING [ CommandProc, Register ],
IO,
Lark,
LarkSmartsMonitorImpl,
Nice,
Process USING [ Detach, SetTimeout, SecondsToTicks ],
Rope USING [ Concat ],
ThParty USING [ Advance, Alert, SetProse ],
ThPartyPrivate USING [ DehandleSmarts, GetCurrentParty, SmartsBody, SmartsData ],
Thrush USING [
CallUrgency, ConvEvent, ConversationHandle, Disposition, H, IntervalSpec, IntervalSpecs, PartyHandle, NB, nullConvHandle, nullHandle, ProseSpec, ProseSpecBody, ProseSpecs, Reason, ROPE, SmartsHandle, StateID, StateInConv, ThHandle ],
ThSmartsPrivate USING [
ConvDesc, ConvDescBody, Deregister, EnterLarkState, LarkFailed, LarkState, OpenConversations, ParseState, SmartsInfo, SmartsInfoBody ],
ThSmartsRpcControl,
Triples USING [ Select ],
TU,
VoiceUtils USING [ Problem, ProblemFR, Report, ReportFR ]
;
LarkSmartsSupImpl: CEDAR MONITOR LOCKS root
IMPORTS
Commander,
IO,
Process,
root: LarkSmartsMonitorImpl,
Nice,
Rope,
ThParty,
ThPartyPrivate,
Thrush,
ThSmartsPrivate,
Triples,
TU,
VoiceUtils
EXPORTS ThSmartsPrivate
SHARES LarkSmartsMonitorImpl = {
OPEN IO;
Copies
CallUrgency: TYPE = Thrush.CallUrgency;
CommandEvents: TYPE = Lark.CommandEvents;
ConversationHandle: TYPE = Thrush.ConversationHandle;
nullConvHandle: ConversationHandle=Thrush.nullConvHandle;
ConvDesc: TYPE = ThSmartsPrivate.ConvDesc;
ConvEvent: TYPE = Thrush.ConvEvent;
disabled: Lark.Event = Lark.disabled;
enabled: Lark.Event = Lark.enabled;
endNum: Lark.Event = Lark.endNum;
H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; };
IntervalSpec: TYPE = Thrush.IntervalSpec;
IntervalSpecs: TYPE = Thrush.IntervalSpecs;
ProseSpec: TYPE = Thrush.ProseSpec;
ProseSpecs: TYPE = Thrush.ProseSpecs;
LarkState: TYPE = ThSmartsPrivate.LarkState;
NB: TYPE = Thrush.NB;
nullHandle: Thrush.ThHandle = Thrush.nullHandle;
OpenConversations: TYPE = ThSmartsPrivate.OpenConversations;
PartyHandle: TYPE = Thrush.PartyHandle;
Reason: TYPE = Thrush.Reason;
ROPE: TYPE = Thrush.ROPE;
SHHH: TYPE = Lark.SHHH; -- Encrypts conv. if first arg to RPC PROC
SmartsHandle: TYPE = Thrush.SmartsHandle;
SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo;
SmartsInfoBody: TYPE = ThSmartsPrivate.SmartsInfoBody;
StateInConv: TYPE = Thrush.StateInConv;
StatusEvents: TYPE = Lark.StatusEvents;
Ctr: TYPE = RECORD[
count: INT,
stop: INT
];
PD: TYPE = RECORD [
defaultRecordLength: INT ← -1,
timeoutNoAction: INTEGER ← 5,
cPr: REF Ctr←NEW[Ctr←[0,1000000]],
cSp: REF Ctr←NEW[Ctr←[0,1000000]],
cRs: REF Ctr←NEW[Ctr←[0,1000000]],
cZp: REF Ctr←NEW[Ctr←[0,1000000]],
cNw: REF Ctr←NEW[Ctr←[0,1000000]],
doReports: BOOLFALSE,
doNice: BOOLFALSE
];
pd: REF PDNEW[PD←[]];
Report: PROC[what: ROPE, info: SmartsInfo, ctr: REF Ctr] = {
IF NOT pd.doReports THEN RETURN;
VoiceUtils.Report[what, $Lark, info.larkInfo];
ctr.count𡤌tr.count+1;
IF ctr.count>ctr.stop THEN { VoiceUtils.Problem["Report overflow", $Lark, info.larkInfo]; };
};
ReportFR: PROC[what: ROPE, info: SmartsInfo, ctr: REF Ctr, a1, a2: IO.Value←rope[NIL]] = {
IF NOT pd.doReports THEN RETURN;
VoiceUtils.ReportFR[what, $Lark, info.larkInfo, a1, a2];
ctr.count𡤌tr.count+1;
IF ctr.count>ctr.stop THEN { VoiceUtils.Problem["Report overflow", $Lark, info.larkInfo]; };
};
BeNice: PROC[r: REF, d: INT, info: SmartsInfo] = {
IF NOT pd.doNice THEN RETURN;
Nice.BeNice[r, d, $Lark, info.larkInfo];
};
Party-invoked actions
LarkProgress: PUBLIC ENTRY PROC[
interface: ThSmartsRpcControl.InterfaceRecord,
shh: SHHH,
smartsID: Thrush.SmartsHandle,
event: Thrush.ConvEvent,
yourParty: BOOL,
latestEvent: BOOL,
informationOnly: BOOL
] RETURNS [ d: Thrush.Disposition ] = {
info: SmartsInfo ← GetSmartsInfo[smartsID: smartsID];
cDesc: ThSmartsPrivate.ConvDesc;
IF info=NIL THEN RETURN[pass];
d�tedAndStop;
Update local state information
IF pd.doReports THEN Report[
Rope.Concat[
IO.PutFR["---- LkProg: %t(%d) %g %g yr=%g ",
time[event.credentials.convID], int[event.credentials.stateID],
refAny[NEW[StateInConv𡤎vent.state]], TU.RefAddr[info], bool[yourParty]],
IO.PutFR["lt=%g in=%g, ky=%g\n",
bool[latestEvent], bool[event.intervalSpecs#NIL OR event.proseSpecs#NIL], bool[event.keyTable#NIL]]],
info, pd.cPr];
cDesc ← GetConv[info, event.credentials.convID, FALSE];
IF event.credentials.stateID <= cDesc.cState.credentials.stateID THEN RETURN[pass]; -- Old news!
Fields always extracted
cDesc.cState.credentials.smartsID ← smartsID;
cDesc.cState.credentials.stateID ← event.credentials.stateID;
<<Need to check for increasing stateID here, and reject old ones? If so, enable
test in alrt case below.>>
Extracted if present
IF event.keyTable#NIL THEN {
cDesc.cState.keyTable ← event.keyTable; cDesc.newKeys←TRUE; };
IF event.intervalSpecs#NIL THEN
May accept more later.
EnqueueIntervals[cDesc, event.intervalSpecs];
IF event.proseSpecs#NIL THEN {
req: BOOLFALSE;
FOR pSL: ProseSpecs ← event.proseSpecs, pSL.rest WHILE pSL#NIL DO
IF pSL.first.type=request THEN {
req ← TRUE;
IF ~pSL.first.queueIt AND info.larkInfo.textToSpeech THEN {
Flush proseSpecs that haven't been sent yet. It doesn't matter if we remove started and finished reports here; the server doesn't care about those anyway. But what about REFs? Will no one else get to see these either?
event.proseSpecs ← pSL;
cDesc.newProses ← NIL;
};
};
ENDLOOP;
IF req OR ~info.larkInfo.textToSpeech THEN
EnqueueProses[cDesc, event.proseSpecs];
};
IF event.address#NIL THEN { cDesc.cState.address𡤎vent.address; cDesc.newAddress←TRUE; };
Extracted if the event changes our state.
IF yourParty THEN {
cDesc.descValid ← TRUE;
cDesc.cState.credentials.partyID ← event.credentials.partyID;
cDesc.cState.state ← event.state;
cDesc.cState.comment ← event.comment;
cDesc.cState.reason ← event.reason;
<< When Conferencing is added, put this back in.>>
cDesc.cState.conferenceHost ← event.conferenceHost;
IF event.spec#NIL THEN { cDesc.cState.spec ← event.spec; cDesc.newSpec←TRUE; };
Extracted if non-standard?
IF event.comment#NIL THEN cDesc.cState.comment ← event.comment;
IF event.urgency#normal THEN cDesc.cState.urgency ← event.urgency;
IF event.alertKind#standard THEN cDesc.cState.alertKind ← event.alertKind;
SELECT event.state FROM
reserved, parsing, initiating => cDesc.originator ← us;
maybe => {
cDesc.originator ← us;
Yucchh! Progress is shared between Trunk and Lark smarts. Want to do it only in the Lark case. This is the only way to tell, at present!
IF info.Supervise = LarkSupervise THEN info.larkInfo.ringTune ← event.ringTune;
};
pending => cDesc.originator ← them;
ringing => { cDesc.originator ← them; info.larkInfo.ringTune ← event.ringTune; };
ENDCASE;
};
BeNice[event, 4, info];
BeNice[cDesc, 6, info];
cDesc.newEvent ← TRUE;
IF latestEvent THEN Apprise[info]; -- Wait for the last report to wake process.
};
Th(e) Process
LarkSupervise: PUBLIC ENTRY PROC[info: SmartsInfo ] = {
TRUSTED {
Process.SetTimeout[@info.thAction, Process.SecondsToTicks[pd.timeoutNoAction]]; };
IF info.apprise THEN DO
ENABLE {
UNWIND => NULL;
ThSmartsPrivate.LarkFailed => GOTO Failing;
};
prevL: OpenConversations ← NIL;
nb: NB←success;
convL: OpenConversations;
trans: Transition;
info.apprise ← FALSE;
FOR convL ← info.conversations,
convL.rest WHILE convL#NIL DO
cDesc: ConvDesc = convL.first;
stateNow: StateInConv = cDesc.cState.state;
ours: BOOL ← ( cDesc.cState.credentials.convID = info.currentConvID );
IF pd.doReports THEN Report[
Rope.Concat[
IO.PutFR["**** LkSup: %t(%d) %g %g->%g",
time[cDesc.cState.credentials.convID], int[cDesc.cState.credentials.stateID],
TU.RefAddr[info], refAny[NEW[StateInConv←stateNow]], refAny[NEW[StateInConv�sc.desiredState]]],
IO.PutFR[" %g%g\n",
refAny[NEW[Transition←transForStates[stateNow][cDesc.desiredState]]],
rope[IF ours THEN " (ours)" ELSE ""]]],
info, pd.cSp];
BeNice[cDesc, 6, info];
IF NOT cDesc.descValid THEN LOOP;
IF info.currentConvID = nullConvHandle --AND stateNow#idle-- THEN {
<<This stuff feels like it's in the wrong place. Will feel more so when multi-calls
are dealt with. >>
ours←TRUE; info.currentConvID ← cDesc.cState.credentials.convID;
};
IF stateNow=idle THEN {
Conv. is now idle: forget about it or re-use it, sort of.
Remove dead conversation from list.
IF pd.doReports THEN
ReportFR[" ** Zap %t\n", info, pd.cZp, time[cDesc.cState.credentials.convID]];
IF prevL#NIL THEN {
prevL.rest ← convL.rest; convL ← prevL; }
ELSE info.conversations𡤌onvL.rest;
IF ours THEN {
reason: Reason = cDesc.cState.reason;
newConvID: ConversationHandle�sc.cState.credentials.convID;
newDesc: ConvDesc;
info.currentConvID ← nullConvHandle;
SELECT info.larkInfo.hookState FROM
onhook, spkr =>
SELECT reason FROM
terminating, wontSay => GOTO Exit;
ENDCASE => IF cDesc.originator#us THEN GOTO Exit;
ENDCASE =>
SELECT TRUE FROM
reason=terminating, reason=wontSay, cDesc.originator#us => {
Set to look like reserving brand new conversation
newConvID ← nullConvHandle;
info.currentConvID ← nullConvHandle;
};
ENDCASE;
newDesc ← GetConv[info, newConvID, TRUE];
ChangeState[info, newDesc, reserved, cDesc.cState.reason, cDesc.cState.comment];
-- Now go around the loop once, if only to coerce Lark into idle state.
EXITS Exit => NULL;
};
}
ELSE IF NOT ours THEN
Conv isn't the one we're interested in, and doesn't look like it's going idle: idle it.
Should probably consult transForStates for validity.
nb ← ThParty.Advance[
credentials: cDesc.cState.credentials,
state: idle,
reason: busy,
comment: "One conversation at a time, please."
]
ELSE {
State and substate (below) and desired state indicate there's something to do. Do it:
SELECT (trans←transForStates[stateNow][cDesc.desiredState]) FROM
noop => NULL;
elim => ERROR; -- handled in stateNow=idle case above.
rsrv, rers, prsg, alrt => { -- placing call, or reserving conversation
convID: ConversationHandle;
calledPartyID: PartyHandle =
IF trans#alrt THEN nullHandle ELSE cDesc.desiredPartyID;
nb ← IF trans=alrt AND calledPartyID=nullHandle
THEN noSuchParty2 ELSE success;
IF NOT ours THEN Problem["What to do in a race?", info];
IF nb=success THEN [nb, convID] ← ThParty.Alert [
credentials: cDesc.cState.credentials,
calledPartyID: calledPartyID,
state: IF trans = alrt THEN initiating ELSE cDesc.desiredState,
reason: cDesc.desiredReason,
newConv: trans=rsrv,
comment: cDesc.desiredComment
];
IF nb=success THEN {
cDesc.cState.credentials.convID ← info.currentConvID ← convID;
ours←TRUE;
};
};
idle, actv => -- Simple transitions
nb ← ThParty.Advance [
credentials: cDesc.cState.credentials,
state: cDesc.desiredState,
reason: cDesc.desiredReason,
comment: cDesc.desiredComment
];
spvs => { -- Supervision while active.
cDesc.desiredState�tive; -- Reflect reality
FOR iL: IntervalSpecs ← cDesc.newIntervals, iL.rest WHILE iL#NIL DO
May do more later. For now, record the intervals that start; when you see the last one that started end, it's time to shut down the connection.
iS: IntervalSpec = iL.first;
IF iS.interval.length#0 OR iS.queueIt THEN -- else flush: ignore
SELECT iS.type FROM
started => cDesc.desiredIntID ← iS.intID;
finished =>
IF iL.rest=NIL AND iS.intID = cDesc.desiredIntID THEN
SELECT info.larkInfo.hookState FROM
spkr => ChangeState[info, cDesc, idle]; ENDCASE;
ENDCASE;
ENDLOOP;
cDesc.newIntervals ← NIL;
EnterLarkState, below, may cause new keys to be distributed.
When voice messages again supported, will need to initiate intervals here.
IF cDesc.newProses#NIL AND info.larkInfo.textToSpeech THEN {
copyNewProses: ProseSpecs ← cDesc.newProses;
cDesc.newProses ← NIL;
EnqueueProses[cDesc, copyNewProses];
Make another copy of the newProses -- this copy will belong only to the Lark (but it may include started and finished reports, which the Lark must ignore). We can then smash the prose ROPE of the original newProses inside the loop below.
ThSmartsPrivate.EnterLarkState[
info.larkInfo, LarkStateForState[cDesc, stateNow, info.larkInfo.larkState], info];
cDesc.newProses ← copyNewProses;
};
FOR pL: ProseSpecs ← cDesc.newProses, pL.rest WHILE pL#NIL DO
May do more later. For now, record the requests that start; when you see the last one that started end, it's time to shut down the connection.
pS: ProseSpec = pL.first;
SELECT pS.type FROM
request => IF info.larkInfo.textToSpeech THEN {
pS.type ← started;
pS.prose ← "";
Avoid sending long RPC packets back to acknowledge things
};
started => cDesc.desiredProseID ← pS.intID;
finished =>
IF ~info.larkInfo.textToSpeech AND pL.rest=NIL AND pS.intID = cDesc.desiredProseID THEN
SELECT info.larkInfo.hookState FROM
spkr => ChangeState[info, cDesc, idle];
ENDCASE;
ENDCASE;
ENDLOOP;
IF cDesc.newProses#NIL AND info.larkInfo.textToSpeech THEN {
nb ← ThParty.SetProse[
shhh: info.larkInfo.shh,
credentials: cDesc.cState.credentials,
proseSpecs: cDesc.newProses
];
IF nb=success THEN cDesc.newProses←NIL;
}
ELSE
cDesc.newProses ← NIL;
};
EnterLarkState, below, may cause new keys to be distributed.
When voice messages again supported, will need to initiate intervals here.
ring => -- This is how you say you'll ring an incoming call
IF info.larkInfo.autoAnswer THEN {
info.apprise←TRUE;
cDesc.desiredState ← active;
}
ELSE nb ← ThParty.Advance [
credentials: cDesc.cState.credentials,
state: ringing
];
invl => {
comment: ROPE="Invalid state transition";
Problem[comment, info];
ChangeState[info, cDesc, idle, error, comment];
};
ntiy => {
comment: ROPE= "Unimplemented state transition";
Problem[comment, info];
ChangeState[info, cDesc, idle, error, comment];
};
ENDCASE => ERROR;
};
Analyze any results of trying to reach a different state.
IF nb#success THEN
ReportFR[" ** Results: nb=%g\n", info, pd.cRs, refAny[NEW[Thrush.NB←nb]]];
SELECT nb FROM
success, stateMismatch => NULL;
noSuchParty2, narcissism => -- Have to get to error tone here. No such party.
ChangeState[info, cDesc, idle, notFound, "Called party not found, or calling self"];
partyNotEnabled => ours←FALSE;
invalidTransition, convNotActive, convStillActive => {
Complain and transition to idle
comment: ROPE="Party-level detected invalid state transition request";
Problem[comment, info];
ChangeState[info, cDesc, idle, error, comment];
};
notInConv, noSuchConv => { -- Complain, zap, go idle and repeat.
comment: ROPE="NotInConv or NoSuchConv";
Problem[comment, info];
IF ours THEN info.currentConvID ← nullConvHandle;
cDesc.cState.credentials.convID ← nullConvHandle;
cDesc.cState.credentials.stateID ← 0;
ChangeState[info, cDesc, idle, error, comment];
};
noSuchParty, noSuchSmarts => { -- Complain, deregister, we gone! Needs tuning.
Problem[
"LkSmts: NoSuchParty or NoSuchSmarts reported, must try to go away", info];
GOTO Failing;
};
ENDCASE => ERROR;
Set up switching and tones to match state.
IF ours THEN ThSmartsPrivate.EnterLarkState[
info.larkInfo, LarkStateForState[cDesc, stateNow, info.larkInfo.larkState], info];
prevL ← convL;
ENDLOOP;
IF NOT info.apprise THEN WAIT info.thAction;
IF info.conversations = NIL THEN EXIT;
REPEAT Failing => ThSmartsPrivate.Deregister[info]; -- now Failed
ENDLOOP;
info.thProcess ← NIL;
};
Connection Management Utilities
GetConv: PUBLIC INTERNAL PROC[info: SmartsInfo, convID: ConversationHandle, validIfNew: BOOL
] RETURNS [ cDesc: ConvDesc←NIL ] = --INLINE-- {
FOR convs: OpenConversations ← info.conversations, convs.rest WHILE convs#NIL DO
IF convs.first.cState.credentials.convID = convID THEN RETURN[convs.first];
ENDLOOP;
cDesc ← NEW[ThSmartsPrivate.ConvDescBody←[]];
cDesc.descValid ← validIfNew;
cDesc.cState.state ← any;
cDesc.cState.credentials ← [ convID: convID, smartsID: H[info.smarts],
partyID: ThPartyPrivate.GetCurrentParty[smartsID: H[info.smarts]], stateID: 0 ];
info.conversations ← CONS[cDesc, info.conversations];
IF pd.doReports THEN
Report[IO.PutFR[" ** NewConv %t %g, vl=%g\n", time[convID], TU.RefAddr[info], bool[validIfNew]], info, pd.cNw];
};
ChangeState: PUBLIC INTERNAL PROC[
info: SmartsInfo,
cDesc: ConvDesc,
state: StateInConv ← idle,
reason: Reason ← wontSay,
comment: ROPENIL
] = {
IF info=NIL OR cDesc=NIL THEN RETURN;
cDesc.desiredState ← state;
cDesc.desiredReason ← reason;
cDesc.desiredComment ← comment;
Apprise[info];
};
Apprise: PUBLIC INTERNAL PROC[info: SmartsInfo] = TRUSTED --INLINE-- {
IF info.thProcess=NIL THEN
Process.Detach[info.thProcess ← FORK info.Supervise[info]];
info.apprise ← TRUE;
NOTIFY info.thAction;
};
EnqueueIntervals: INTERNAL PROC[cDesc: ConvDesc, int: IntervalSpecs] = INLINE {
IF cDesc.newIntervals#NIL THEN cDesc.iTail.rest ← int ELSE cDesc.newIntervals ← int;
FOR iL: IntervalSpecs ← int, iL.rest WHILE iL#NIL DO cDesc.iTail ← iL; ENDLOOP;
};
EnqueueProses: INTERNAL PROC[cDesc: ConvDesc, pro: ProseSpecs] = {
FOR pL: ProseSpecs ← pro, pL.rest WHILE pL#NIL DO
Copies, so that changes can be made in order to report back to ThParty.
newSpec: ProseSpecs ← LIST[NEW[Thrush.ProseSpecBody ← pL.first^]];
IF cDesc.newProses#NIL THEN cDesc.pTail.rest ← newSpec
ELSE cDesc.newProses ← newSpec;
cDesc.pTail ← newSpec;
ENDLOOP;
};
ReportProseDone: PUBLIC ENTRY PROC[info: SmartsInfo, proseSpec: ProseSpec] = {
cDesc: ConvDesc ← GetConv[info, info.currentConvID, FALSE];
proseSpec.type ← finished; -- Check this one!
EnqueueProses[cDesc, LIST[proseSpec]];
cDesc.pTail.first.type ← finished; -- make sure this is okay!
Apprise[info];
};
Other Utilities
GetSmartsInfo: PUBLIC PROC[smartsID: SmartsHandle←nullHandle,
smarts: ThPartyPrivate.SmartsData←NIL]
RETURNS [info: SmartsInfo←NIL] = {
r: REF←smarts;
IF smartsID#nullHandle THEN
r←ThPartyPrivate.DehandleSmarts[smartsID];
IF r#NIL THEN RETURN[NARROW[Triples.Select[$SmartsData, r, --info--]]];
};
Problem: PROC[comment: ROPE, info: SmartsInfo] = {
VoiceUtils.ProblemFR[Rope.Concat["LarkSmarts(%g): ", comment], $Smarts, info, TU.RefAddr[info]];
};
State Transition Tables
larkStateForState: ARRAY StateInConv OF LarkState ← [
idle, reserved, parsing, initiating, pending, maybe, ringing, canActivate, active,
idle, dialTone, silence, silence, silence, ringBack, ringing, silence, talking,
inActive, any
silence, silence
];
LarkStateForState: INTERNAL PROC[cDesc: ConvDesc, state: StateInConv, nowState: LarkState]
RETURNS [larkState: LarkState] = -- INLINE -- {
SELECT (larkState←larkStateForState[state]) FROM
talking => {
spec: Lark.ConnectionSpec = cDesc.cState.spec;
IF spec=NIL THEN ERROR;
IF spec.localSocket.net = spec.remoteSocket.net
AND spec.localSocket.host = spec.remoteSocket.host THEN larkState ← nowState;
};
dialTone => larkState ← SELECT cDesc.cState.reason FROM
busy, notImportantEnough => busyTone,
absent, noCircuits, noParticular, notFound, error => errorTone,
ENDCASE => dialTone;
ENDCASE;
};
Transition: TYPE = {
Just codes to dispatch on in Supervisor; explained there
noop, elim, idle, rsrv, rers, prsg, alrt, ring, actv, spvs, invl, ntiy
};
transForStates: ARRAY StateInConv OF ARRAY StateInConv OF Transition ← [
idle resrv pars init pend mayb ring canAc activ inact any -- desired
[ elim, invl, prsg, invl, invl, invl, invl, invl, elim, elim, elim ], -- idle  (current)
[ idle, noop, prsg, invl, invl, invl, invl, invl, alrt, ntiy, noop ], -- reserved
[ idle, rers, noop, invl, invl, invl, invl, invl, alrt, ntiy, invl ], -- parsing
[ idle, noop, invl, invl, invl, invl, invl, invl, noop, ntiy, noop ], -- initiating
[ idle, invl, invl, invl, invl, invl, invl, invl, actv, ntiy, ring ], -- pending
[ idle, noop, invl, invl, invl, invl, invl, invl, noop, ntiy, noop ], -- maybe
[ idle, invl, invl, invl, invl, invl, invl, invl, actv, ntiy, noop ], -- ringing
[ idle, invl, invl, invl, invl, invl, invl, invl, ntiy, ntiy, ntiy ], -- canActivate
[ idle, spvs, invl, invl, invl, invl, invl, invl, spvs, ntiy, spvs ], -- active
[ idle, invl, invl, invl, invl, invl, invl, invl, ntiy, noop, ntiy ], -- inactive
[ noop, rsrv, prsg, invl, invl, invl, invl, invl, alrt, ntiy, invl ] -- any (nonex)
];
NB: examine relationship to validity table in PartyOpsImpl someday.
Debugging nonsense
ViewCmd: Commander.CommandProc = TRUSTED {
Nice.View[pd, "Lark PD"];
};
Commander.Register["VuLarkSmarts", ViewCmd, "Program Management variables for Lark Smarts"];
}.
Swinehart, May 15, 1985 11:05:22 am PDT
Cedar 6.0, add Prose stuff as direct copy of Interval stuff.
changes to: IntervalSpecs, ProseSpec, ProseSpecs, LarkState, LarkProgress, LarkSupervise, EnqueueProses
Swinehart, May 22, 1985 12:15:11 pm PDT
hotLine => autoAnswer
changes to: LarkSupervise
Swinehart, July 2, 1985 10:09:14 am PDT
Fixing up trunkTalking stuff
changes to: LarkSupervise, LarkStateForState
Polle Zellweger (PTZ) July 11, 1985 6:15:01 pm PDT
changes to: DIRECTORY, EnqueueProses, ReportProseDone, LarkSupervise
Polle Zellweger (PTZ) July 16, 1985 9:42:51 pm PDT
changes to: LarkProgress, LarkSupervise, ReportProseDone
Polle Zellweger (PTZ) July 30, 1985 4:41:39 pm PDT
Handle copying of newProses correctly - give Lark its own copy.
changes to: LarkSupervise
Swinehart, August 6, 1985 2:26:39 pm PDT
Merge PTZ ProseSpec changes
changes to: DIRECTORY, LarkProgress, LarkSupervise, EnqueueProses
Polle Zellweger (PTZ) August 14, 1985 6:12:13 pm PDT
Prose flushing, also fix undesired speakerphone hangup for intervals, proseSpecs.
changes to: LarkProgress, LarkSupervise
Polle Zellweger (PTZ) August 22, 1985 2:04:45 pm PDT
changes to: LarkProgress -- comment out some optimizing queue flushing
Swinehart, May 17, 1986 4:04:37 pm PDT
Cedar 6.1
changes to: DIRECTORY, LarkSmartsSupImpl, Report, ReportFR, Problem