DIRECTORY 
IO,
Lark -- USING [
-- CommandEvents, ConnectionSpec, Event, LarkModel, Passel, SHHH, StatusEvents ]--,
LarkSmartsMonitorImpl,
Nice,
Log USING [ Problem, ProblemHandle, Report ],
Process USING [ SecondsToTicks, SetTimeout ],
Rope USING [ Concat ],
ThParty USING [ Advance, Alert, CreateParty ],
ThPartyPrivate USING [
DehandleParty, DehandleSmarts, LocalSmartsInterface, RegisterLocal, SmartsBody, SmartsData ],
Thrush USING [
ConversationHandle, ConvEvent, PartyHandle, H, MakeUnique, NB, nullConvHandle, nullHandle, pERROR, Reason, ROPE, SmartsHandle, StateInConv, ThHandle ],
ThSmartsPrivate USING [
Apprise, ConvDesc, Deregister, EnterLarkState, GetConv, GetConvDesc, GetSIC, GetSmartsInfo, LarkFailed, LarkProgress, OpenConversations, SmartsInfo, SmartsInfoBody ],
ThSmartsRpcControl,
Triples USING [Any, Make, Select ],
TU
;

LarkTrunkSmartsImpl: CEDAR MONITOR LOCKS root
IMPORTS
root: LarkSmartsMonitorImpl,
IO,
Log,
Nice,
Process,
Rope,
Thrush,
ThParty,
ThPartyPrivate,
ThSmartsPrivate,
ThSmartsRpcControl,
Triples,
TU
EXPORTS ThSmartsPrivate --, ThSmarts via Interface record --
SHARES LarkSmartsMonitorImpl = { OPEN IO;


ConvDesc: TYPE = ThSmartsPrivate.ConvDesc;
H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; };
ROPE: TYPE = Thrush.ROPE;
SHHH: TYPE = Lark.SHHH;  -- Encrypts conv. if first arg to RPC PROC
PartyHandle: TYPE = Thrush.PartyHandle;
nullHandle: Thrush.ThHandle = Thrush.nullHandle;
nullConvHandle: Thrush.ConversationHandle = Thrush.nullConvHandle;
SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo;
StateInConv: TYPE = Thrush.StateInConv;

PD: TYPE = RECORD [
timeoutNoAction: INT_30,
cSp: REF Ctr_NEW[Ctr_[0,1000000]],
cRs: REF Ctr_NEW[Ctr_[0,1000000]],
cZp: REF Ctr_NEW[Ctr_[0,1000000]],
doReports: BOOL_FALSE,
doNice: BOOL_FALSE
];
pd: REF PD _ NEW[PD_[]];

Ctr: TYPE = RECORD[
count: INT,
stop: INT
];
Report: PROC[what: ROPE, info: SmartsInfo, ctr: REF Ctr] = {
IF NOT pd.doReports THEN RETURN;
Log.Report[what, $Lark, info.larkInfo];
ctr.count_ctr.count+1;
IF ctr.count>ctr.stop THEN { Log.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];
};


RegisterTrunk: PUBLIC ENTRY PROC[
hostPartyID: PartyHandle, hostSmarts: ThPartyPrivate.SmartsData, hostInfo: SmartsInfo ]
RETURNS [ smartsID: Thrush.SmartsHandle ] = { {
ENABLE UNWIND => NULL;
localSmarts: ThPartyPrivate.LocalSmartsInterface;
info: SmartsInfo;
partyID: PartyHandle = ThParty.CreateParty[type: trunk];
hostParty: REF = ThPartyPrivate.DehandleParty[hostPartyID];
party: REF = ThPartyPrivate.DehandleParty[partyID];
smarts: ThPartyPrivate.SmartsData;
IF hostParty=NIL OR party = NIL THEN
RETURN[Log.ProblemHandle["TrunkSmarts didn't register", $Party, nullHandle, hostParty]];
Thrush.MakeUnique[$TrunkParty, hostParty, party];
localSmarts _ ThSmartsRpcControl.NewInterfaceRecord[];
localSmarts.Progress _ ThSmartsPrivate.LarkProgress;
smartsID _ ThPartyPrivate.RegisterLocal [
partyID: partyID,
interface: localSmarts,
properties: hostSmarts.properties
];
IF smartsID = nullHandle THEN GOTO NotSmart;
smarts _ ThPartyPrivate.DehandleSmarts[smartsID, TRUE];
info _ NEW[ThSmartsPrivate.SmartsInfoBody _ [
smarts: smarts,
otherSmarts: hostSmarts,
ParseEvent: LarkTrunkParseEvent,
Supervise: TrunkSupervise,
larkInfo: hostInfo.larkInfo ]];
Triples.Make[$SmartsData, smarts, info]; 
EXITS
NotSmart => RETURN[nullHandle]; }; };


LarkTrunkParseEvent: ENTRY PROC[
smartsInfo: SmartsInfo, sEvent: Lark.StatusEvent] = {
ENABLE {
UNWIND=>NULL;
ThSmartsPrivate.LarkFailed => { Log.Problem["Lark Failed", $Smarts, smartsInfo]; GOTO Failed; };
ANY => { Log.Problem[, $Smarts, smartsInfo]; GOTO Failed; };
};
SELECT sEvent.device FROM
ringDetect => SELECT sEvent.event FROM
Lark.enabled => CmdCall[smartsInfo];
Lark.disabled => CmdOnhook[smartsInfo];
ENDCASE => ERROR Thrush.pERROR;
tones =>
IF sEvent.event = 'F THEN CmdAnswer[smartsInfo];
ENDCASE;
EXITS
Failed =>
ThSmartsPrivate.Deregister[ThSmartsPrivate.GetSmartsInfo[smarts: smartsInfo.otherSmarts]];
};

CmdCall: INTERNAL PROC[info: SmartsInfo] = {
calledPartyID: PartyHandle;
cDesc: ConvDesc;
SELECT ThSmartsPrivate.GetSIC[info] FROM
idle => NULL;
ENDCASE => RETURN; -- not a valid time for this call.  Ignore.  Host system will handle.
cDesc _ ThSmartsPrivate.GetConv[info, nullConvHandle, TRUE];
calledPartyID _ H[Triples.Select[$TrunkParty, --owner--,
ThPartyPrivate.DehandleParty[cDesc.cState.credentials.partyID]]]; --<<UGH!>>
IF calledPartyID = nullHandle THEN RETURN;
cDesc.desiredState _ active;
cDesc.desiredPartyID _ calledPartyID;
cDesc.desiredReason _ wontSay;
cDesc.desiredComment _ NIL;
cDesc.cState.state _ any; -- meaning "This is a new conversation to be made."
ThSmartsPrivate.Apprise[info];
};

CmdOnhook: INTERNAL PROC[info: SmartsInfo] = {
cDesc: ConvDesc=ThSmartsPrivate.GetConvDesc[info];
IF cDesc=NIL THEN RETURN;
SELECT cDesc.cState.state FROM
initiating, maybe => NULL; -- ringing stopped before called party answered.
ENDCASE => RETURN; -- already active or something; ignore end of ringing
cDesc.desiredState_idle;
cDesc.desiredReason _ wontSay;
cDesc.desiredComment _ NIL;
ThSmartsPrivate.Apprise[info];
};

CmdAnswer: INTERNAL PROC[info: SmartsInfo] = {
cDesc: ConvDesc=ThSmartsPrivate.GetConvDesc[info];
IF cDesc=NIL THEN RETURN;
SELECT cDesc.cState.state FROM
pending => NULL;	-- this is the only state in which we expect any such action.
ENDCASE => RETURN;
cDesc.desiredState _ active;
ThSmartsPrivate.Apprise[info];
};


TrunkSupervise: 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;
ANY => { Log.Problem[NIL, $Smarts, info]; GOTO Failing; };
};
prevL: ThSmartsPrivate.OpenConversations _ NIL;
nb: Thrush.NB_success;
convL: ThSmartsPrivate.OpenConversations;
trans: TrkTransition;
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["**** TkSup: %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_cDesc.desiredState]]],
IO.PutFR[" %g%g\n",
refAny[NEW[TrkTransition_trkTransForStates[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 {
ours_TRUE; info.currentConvID _ cDesc.cState.credentials.convID;
};
IF stateNow#idle AND (NOT ours) THEN
nb _ ThParty.Advance[
credentials: cDesc.cState.credentials,
state: idle,
reason: busy,
comment: "One conversation at a time, please."
]
ELSE {
SELECT (trans_trkTransForStates[stateNow][cDesc.desiredState]) FROM
noop => NULL;
elim => {
IF pd.doReports THEN Report[IO.PutFR["  ** Zap: %t\n",
time[cDesc.cState.credentials.convID]], info, pd.cZp];
IF prevL#NIL THEN {
prevL.rest _ convL.rest; convL _ prevL; }
ELSE info.conversations_convL.rest;
IF ours THEN {
info.currentConvID _ nullConvHandle;
IF info.larkInfo.larkState=trunkForwarding THEN
ThSmartsPrivate.EnterLarkState[info.larkInfo, idle, info];
};
};
alrt => { -- placing call
convID: Thrush.ConversationHandle;
[nb, convID] _ ThParty.Alert [
credentials: cDesc.cState.credentials,
calledPartyID: cDesc.desiredPartyID,
state: initiating
];
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 => {
spec: Lark.ConnectionSpec = cDesc.cState.spec;
IF cDesc.newEvent AND spec#NIL AND (spec.localSocket.net # spec.remoteSocket.net
OR spec.localSocket.host # spec.remoteSocket.host) THEN
ThSmartsPrivate.EnterLarkState[info.larkInfo, trunkForwarding, info];
cDesc.newIntervals _ NIL; -- Ignore interval Specs.
};
pend => { -- Handle an incoming (from Etherphone) call.
info.phoneNumber _ cDesc.cState.address;
IF info.phoneNumber = NIL THEN {
cDesc.desiredState_active;
info.apprise _ TRUE;
}
ELSE IF NOT cDesc.signallingStarted THEN
ThSmartsPrivate.EnterLarkState[info.larkInfo, trunkSignalling, info];
cDesc.signallingStarted_TRUE;
};
invl => {
Log.Problem["LarkSmarts: Invalid state transition request.", $Smarts, info];
info.apprise_TRUE;
cDesc.desiredState _ idle;
cDesc.desiredReason _ error;
cDesc.desiredComment _ "Invalid state transition";
};
ntiy => {
Log.Problem["LarkSmarts: State transition not yet implemented.", $Smarts, info];
info.apprise_TRUE;
cDesc.desiredState _ idle;
cDesc.desiredReason _ error;
cDesc.desiredComment _ "Unimplemented state transition";
};
ENDCASE => Thrush.pERROR;
};

IF nb#success THEN
Report[IO.PutFR["  ** Results: nb=%g\n", refAny[NEW[Thrush.NB_nb]]], info, pd.cRs];
SELECT nb FROM
success, stateMismatch => NULL;
noSuchParty2, narcissism => { -- Have to get to error tone here.  No such party.
Log.Problem["Called party not found, or calling self", $Smarts, info];
cDesc.cState.comment _ NIL;
cDesc.cState.reason _ notFound;
cDesc.desiredState_idle;
info.apprise_TRUE;
};
partyNotEnabled => { -- See old version; vamp until enabled.
Log.Problem["Party not yet enabled, ignore as much as possible.", $Smarts, info];
};
invalidTransition, convNotActive, convStillActive => {
comment: ROPE="Party-level detected invalid state transition request";
Log.Problem[comment, $Smarts, info];
cDesc.desiredState _ idle;
cDesc.cState.comment _ comment;
cDesc.cState.reason _ error;
info.apprise_TRUE;
};
notInConv, noSuchConv => { -- Complain, zap, go idle and repeat.
comment: ROPE="NotInConv or NoSuchConv";
Log.Problem[comment, $Smarts, info];
IF ours THEN info.currentConvID _ nullConvHandle;
cDesc.cState.credentials.convID _ nullConvHandle;
cDesc.cState.credentials.stateID _ 0;
cDesc.desiredState _ idle;
cDesc.cState.comment _ comment;
cDesc.cState.reason _ error;
info.apprise_TRUE;
};
noSuchParty, noSuchSmarts => { -- Complain, deregister, we gone! Needs tuning.
Log.Problem[
"NoSuchParty or NoSuchSmarts reported, must try to go away", $Smarts, info];
GOTO Failing;
};
ENDCASE => Thrush.pERROR;
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;
};

TrkTransition: TYPE = {
noop, elim, idle, alrt, pend, actv, spvs, invl, ntiy
};

trkTransForStates: ARRAY StateInConv OF ARRAY StateInConv OF TrkTransition _ [
[ elim, invl, invl,    invl, invl, invl, invl, invl,   elim, ntiy,   elim ], -- idle	 (current)
[ invl, invl, invl,    invl, invl, invl, invl, invl,   invl, invl,    invl ], -- reserved
[ invl, invl, invl,    invl, invl, invl, invl, invl,   invl, invl,    invl ], -- parsing
[ idle, invl, invl,    noop, invl, invl, invl, invl,   noop, ntiy,   invl ], -- initiating

[ idle, invl, invl,    invl, invl, invl, invl, invl,   actv, ntiy,    pend ], -- pending
[ idle, invl, invl,    invl, invl, noop, invl, invl,   noop, ntiy,   invl ], -- maybe
[ invl, invl, invl,    invl, invl, invl, invl, invl,   invl, ntiy,    invl ], -- ringing
[ ntiy, invl, invl,    invl, invl, invl, invl, invl,   ntiy, ntiy,    invl ], -- canActivate

[ idle, invl, invl,    invl, invl, invl, invl, invl,   spvs, ntiy,   invl ], -- active
[ ntiy, invl, invl,    invl, invl, invl, invl, invl,   ntiy, noop,   invl ], -- inactive
[ elim, invl, invl,   invl, invl, invl, invl, invl,   alrt, ntiy,     invl ] -- any (nonex)
];

Nice.View[pd, "Lark Trunk PD"];
}.

��	Š��LarkTrunkSmartsImpl.mesa
Smarts for the Lark "Back Door"
Last modified by D. Swinehart, December 10, 1983 2:00 am

Note: Incoming calls are those from the Etherphone to the outside party, whom this system represents.  Outgoing calls are those from the outside world to an Etherphone.  Remember; trunk party is a representative of people in the public telephone system.
Types and Constants
Initialization
There's no provision here at all for reregistration.  Yet.
Events
RecordTrunkEvent handles events from the EtherPhone Trunk connection.
The only interesting events at present are "ring" (place trunk->station call) and "tones F" (station->trunk call being "answered")
The upstream code produces a single "enabled" event when the line starts ringing, and a single "disabled" event when it appears that ringing has stopped.  This "disabled" event must be anticipated and ignored if the station answers (calling trunk can't hang up on completed call!)
Ignore the incoming call.  It will be handled as unanswered by the host telephone system.
Supervision

<<This stuff feels like it's in the wrong place.  Will feel more so when multi-calls
are dealt with. >>
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.
State and substate (below) and desired state indicate there's something to do. Do it:
Conv. is now idle: forget about it. 
Remove dead conversation from list.
cDesc.cState.credentials.stateID _ 0;
Direct access to outside line requested.
Request signalling.
<<ELSE timeout with signalling not complete . . . shut down??>>
Analyze any results of trying to reach a different state.

Complain and transition to idle
Just codes to dispatch on in Supervisor; explained there
  idle  resrv  pars    init pend mayb ring canAc   activ inact   any -- desired

Debugging nonsense


<< Comments left over from previous system.  Think about it all sometime.  was in section involving analysis of new pending state. >>
<<This is here to deal with the case where we saw ringing, launched a call, were rebuffed by the selected station, and thus went idle.  Now we look available even though the phone is still ringing.  Alternative to having a hook state for the back door is to enter the reserved state on rebuff until the disabled event comes in (caller gives up or is transferred.)>>
nb _ ChangeState[info, busy, "Sorry, trunk in use"]; RETURN; };
Ê4��˜�Jšœ™Jšœ™Jšœ8™8J™�J™ýJ˜�šÏk	œ˜
Jšœ˜šœÏc
˜JšžRœ˜S—J˜J˜Jšœœ$˜-Jšœœ ˜-Jšœœ˜Jšœœ!˜.šœœ˜Jšœ]˜]—šœœ˜Jšœ,œœ.œ(˜——šœœ˜Jšœ¦˜¦—J˜Jšœœ˜#J˜J˜J˜�—šœ
œœ˜-š˜J˜Jšœ˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜—Jšœž$˜<Jšœœœ˜)J˜�—™J˜�Jšœ
œ˜*Jšœœœœœœœ˜JJšœœ
œ˜Jšœœœž*˜CJšœ
œ˜'J˜0J˜BJšœœ˜.Jšœ
œ˜'J˜�šœœœ˜Jšœœ˜Jšœœœ˜"Jšœœœ˜"Jšœœœ˜"Jšœœœ˜Jšœœ˜J˜—Jš	œœœœœ˜J˜�šœœœ˜Jšœœ˜Jšœ˜	J˜—šÏnœœœœ	˜<Jšœœœœ˜ J˜'J˜Jšœœ;˜UJ˜—J˜�šŸœœœœ˜2Jšœœœœ˜J˜(J˜J˜�——™J˜�šŸ
œœ
œ˜!JšœW˜WJšœ(˜/Jšœœœ˜J™:Jšœ1˜1J˜J˜8Jšœœ-˜;Jšœœ)˜3J˜"š	œœœ	œ˜$JšœR˜X—J˜1Jšœ6˜6Jšœ4˜4˜)J˜J˜Jšœ!˜!Jšœ˜—Jšœœœ
˜,Jšœ1œ˜7šœœ#˜-J˜J˜J˜ Jšœ˜Jšœ˜—J˜)š˜Jšœœ˜%—J˜�——™JšœE™EJšœ‚™‚J™˜J˜�šŸœœœ˜ Jšœ5˜5šœ˜Jšœœ˜
JšœQœ˜`Jšœ*œ˜<J˜—šœ˜šœœ˜&J˜$J˜'Jšœœ˜—˜Jšœœ˜0—Jšœ˜—š˜˜	J˜Z——Jšœ˜J˜�—šŸœœœ˜,J˜J˜šœ˜(Jšœœ˜
JšœœžE˜X—Jšœ6œ˜<šœœž	œ˜8JšœBž
˜L—šœœœ˜*J™Y—J˜Jšœ%˜%J˜Jšœœ˜Jšœž3˜MJ˜Jšœ˜—J˜�šŸ	œœœ˜.J˜2Jšœœœœ˜šœ˜Jšœœž0˜KJšœœž5˜H—J˜J˜Jšœœ˜J˜J˜J˜�—šŸ	œœœ˜.J˜2Jšœœœœ˜šœ˜Jšœœ?˜NJšœœ˜—J˜J˜Jšœ˜—J˜�—™J˜�šŸœœœ˜1šœ˜	JšœR˜R—šœœ˜šœ˜Jšœœ˜Jšœœ	˜+Jšœœœ˜:J˜—Jšœ+œ˜/Jšœœ	˜Jšœ)˜)J˜Jšœœ˜šœ˜Jšœœœ˜J˜Jšœ+˜+Jšœœ<˜FJ˜�šœœ˜šœ˜šœ&˜(J˜MJšœœ œ#˜b—šœ˜JšœœA˜KJšœœœœ˜'——Jšœ˜—J˜J™�Jšœœœœ˜!šœ%œœ˜?J™gJšœœ7˜@Jšœ˜—šœœœ˜$J™WJ™4˜J˜&J˜J˜
Jšœ.˜.—J˜—šœ˜J™Ušœ9˜CJšœœ˜
šœ	˜	J™$J™#šœœœ˜6Jšœ6˜6—šœœœ˜Jšœ)˜)—Jšœ˜#šœœ˜Jšœ$˜$šœ)˜/J˜:—J˜—Jšœ˜—šœ	ž˜J˜"˜J˜&Jšœ$˜$Jšœ˜Jšœ˜—˜J˜>Jšœ
˜
JšÏs%™%J˜—J˜—šœž˜#šœ˜J˜&Jšœ˜J˜Jšœ˜Jšœ˜——šœ	˜	J˜.šœœœœ.˜PJšœ1˜7JšœE˜E—Jšœœž˜3J˜—šœ
ž-˜7J˜(šœœœ˜ J™(J˜Jšœœ˜J˜—šœœœ˜(J™JšœE˜E—J™?Jšœœ˜J˜—˜	J˜LJšœ
œ˜J˜J˜J˜2J˜—˜	J˜PJšœ
œ˜J˜J˜J˜8J˜—Jšœ˜—J˜—J™9J˜�šœ˜Jšœœ'œœ˜S—J™�šœ˜Jšœœ˜šœž2˜PJšœF˜FJšœœ˜J˜Jšœ˜Jšœ
œ˜J˜—šœž'˜<J˜QJ˜—šœ6˜6Jšœ™Jšœ	œ9˜FJ˜$Jšœ˜J˜J˜Jšœ
œ˜Jšœ˜—šœž%˜@Jšœ	œ˜(Jšœ$˜$Jšœœ%˜1Jšœ1˜1J˜%Jšœ˜J˜J˜Jšœ
œ˜Jšœ˜—šœž/˜Nšœ˜JšœL˜L—Jšœ	˜
J˜—Jšœ˜—J˜Jšœ˜—Jšœœœœ˜,Jšœœœœ˜&Jšœ.ž
˜AJšœ˜—Jšœœ˜J˜J˜�——˜J™8J˜4J˜—J˜�š	œœ
œœ
œ˜NJšœO™OJ™�JšœMž˜_JšœNž˜YJšœNž
˜XJšœMž
˜ZJ˜�JšœNž
˜XJšœMž˜UJšœNž
˜XJšœNž˜\J˜�JšœMž	˜VJšœMž˜XJšœMž˜[—J˜J˜�™Jšœ˜—J˜J™�J™�J™…J™íJšœ5œ™?J˜�—�…—����.r��D0��