DIRECTORY Atom USING [ PropList ], IO USING [ Value ], Lark USING [ CommandEvents, ConnectionSpec, disabled, enabled, Event, KeyTable, LarkModel, o3i1, StatusEvent, ToneSpec, ts0, ts12 ], LarkPlay USING [ ToneList, ToneSpec ], LarkOpsRpcControl USING [ InterfaceRecord ], MBQueue USING [ Queue ], RefID USING [ nullID ], Rope USING [ROPE], BasicTime USING [ GMT ], Thrush USING [ ActionClass, ActionID, ActionReport, ConversationID, ConvEvent, ConvEventBody, Credentials, NB, NetAddress, nullID, nullConvID, PartyID, PartyType, Reason, ROPE, SHHH, SmartsID, StateInConv ], ThParty USING [ PartyInfo ], ThPartyPrivate USING [ SmartsData ], ThSmarts USING [ noneScheduled ], ThSmartsRpcControl USING [ InterfaceRecord ] ; ThSmartsPrivate: CEDAR DEFINITIONS = { SHHH: TYPE = Thrush.SHHH; SmartsData: TYPE = ThPartyPrivate.SmartsData; ParseState: TYPE = { idle, getStr, getSeq, getFeep, getNum, inStr, inSeq, inFeep, inNum, inTossStr }; LarkState: TYPE = { none, -- Initial state idle, -- Phone not in use talking, -- Etherphone conversation in progress trunkSignalling, -- "Feeping" trunkTalking, -- Standard telephone conversation in progress trunkForwarding, -- Like trunkTalking, but call is forwarded to some other Lark trunkFlashing, -- Implementing special switchhook flash ringing, -- Ringing loudly through Lark speaker silence, -- Dial tone has been broken, dialing in progress. dialTone, -- Caller hears dial tone. ringBack, -- Caller hears ringing. busyTone, -- Caller hears busy signal. errorTone -- Caller hears fast busy signal. }; ProgressTones: TYPE = LarkState[dialTone..errorTone]; SwitchState: TYPE = { onhook, telset, speaker, sPEAKER, monitor, mONITOR }; RingDetState: TYPE = { idle, maybe, ring, between }; Orig: TYPE = { unknown, us, them }; AudioSource: TYPE = ATOM; -- = {$telset (NIL), $lineA, $lineB}; click: Lark.Event = Lark.ts0; -- Momentary closure of speaker box switch. spkrOn: Lark.Event = Lark.ts12; -- Longer-than-momentary closure. LSwitches: TYPE = { xBarAll, hook, aSwitch, sideTone, ringO, revert, revertHook, led, spMode, none }; LState: TYPE = RECORD [ voiceMode: Lark.Event_Lark.o3i1, echoStyle: [0..3]_0, xbar: PACKED ARRAY[0..8) OF [0..256) _ ALL[0], lSw: ARRAY LSwitches OF Lark.Event _ ALL[Lark.disabled] ]; SmartsInfo: TYPE = REF SmartsInfoBody; SmartsInfoBody: TYPE = MONITORED RECORD [ smartsID: Thrush.SmartsID, -- back pointer to my smarts. otherSmartsID: Thrush.SmartsID_Thrush.nullID, partyType: Thrush.PartyType_NIL, -- type of party this smarts represents. larkInfo: LarkInfo, conversations: OpenConversations_NIL, requests: MBQueue.Queue_NIL, -- serialize progress reports, requests for actions ParseEvent: PROC[r: REF], -- r is an EventSpecBody; MBQueued Command: PROC[info: SmartsInfo, val: INT_0]_NIL, NoteNewStateP: PROC[cDesc: ConvDesc, convEvent: Thrush.ConvEvent]_NIL, lastTouchpadChar: Lark.Event _ '\000, parseState: ParseState _ $idle, arguments: Rope.ROPE_NIL, argLength: NAT_0, offset: NAT_0, -- kludge allowing more than ten touchpad commands haveArguments, cmdOrRecip, haveOne: BOOLEAN_FALSE, failed: BOOL_FALSE ]; InputEventSpec: TYPE = REF InputEventSpecBody; InputEventSpecBody: TYPE = RECORD [ smartsInfo: SmartsInfo, sEvent: Lark.StatusEvent _ [0, nothing, '\000] ]; OpenConversations: TYPE = LIST OF ConvDesc; ConvDesc: TYPE = REF ConvDescBody; ConvDescBody: TYPE = RECORD [ info: SmartsInfo, -- corresponding to credentials.smartsID (or else!) situation: Thrush.ConvEventBody, -- .self describes current state in conv. keyTable: Lark.KeyTable _ NIL, ringCheckProcess: PROCESS _ NIL, -- For ringing after someone has answered. lastActionID: Thrush.ActionID _ RefID.nullID -- for remembering last-started request, see LarkSmartsSupImpl.LarkReportAction ]; ConvRequest: TYPE = REF ConvRequestBody; ConvRequestBody: TYPE = RECORD [ cDesc: ConvDesc, -- present state, desiredSituation: Thrush.ConvEventBody _ [], bilateral: BOOL ]; LarkInfo: TYPE = REF LarkInfoBody; LarkInfoBody: TYPE = MONITORED RECORD [ interface: LarkOpsRpcControl.InterfaceRecord, -- here's how you make calls to Lark -- shh: SHHH, -- here's what you use to encrypt them -- larkSmartsInfo: SmartsInfo, -- back pointers larkTrunkSmartsInfo: SmartsInfo, -- back pointers netAddress: Thrush.NetAddress, -- <> -- model: Lark.LarkModel, -- what does this Lark look like? -- larkState: LarkState _ $none, -- tone/crossbar/connect state of actual Lark hardware failed: BOOL _ FALSE, -- set when this (instance of) Lark is no longer viable. debugging: BOOL _ FALSE, -- if TRUE, Lark is in development mode: reaction to failure is less drastic. newActions: LIST OF REF_NIL, -- queue of low-level requests to supervisor process lastAction: LIST OF REF_NIL, -- used in request-queue maintenance, larkProcess: PROCESS_NIL, -- maintains same blinkProcess: PROCESS _ NIL, -- created if LED must flash. stateChange: CONDITION, -- larkProcess should notice change inputQueue: MBQueue.Queue _ NIL, audioSource: AudioSource _ NIL, -- e.g., $telset switchState: SwitchState _ $onhook, -- state of switchhook/speakerphone switch... textToSpeech: BOOL_FALSE, -- Prose 2000 or DecTalk synthesizer is available on this Lark. transmitOnly: BOOL_FALSE, -- w/line(A/B), inhibit spkr, rcvr, line(A/B) out for svcs. forwardedCall: BOOL_FALSE, multicasting: BOOL_FALSE, spec: ThParty.PartyInfo_NIL, cSpec: Lark.ConnectionSpec_NIL, keyTable: Lark.KeyTable _ NIL, keySynch: CONDITION, -- used to lock pieces of LarkOutImpl together while keys are distributed keyTableDistrsRequested: INT_0, keyTablesDistributed: INT _ 0, toneSpec: LarkPlay.ToneSpec_NIL, nextToneList: LIST OF LarkPlay.ToneList_NIL, larkToneSpec: Lark.ToneSpec_NIL, swOnTime: CARDINAL_0, ringChangeTime: CARDINAL_0, ringDetState: RingDetState _ $idle, ringDetCondition: CONDITION, ringDetInstance: INT_0, -- timeout routine is relevant only if this matches expectedNotification: Lark.Event _ 'z, receivedNotification: Lark.Event _ 'Y, lastSwitchState: SwitchState _ $onhook, lState: LState _ [lSw: ALL[Lark.enabled]], scratchEv: Lark.CommandEvents _ NIL, nextScheduledCheck: INT _ ThSmarts.noneScheduled, props: Atom.PropList _ NIL, keyboardEventHandler: PROC[info: LarkInfo, sEvent: Lark.StatusEvent], keyboardResetHandler: PROC[info: LarkInfo] ]; LarkCall: TYPE = REF LarkCallBody; LarkCallBody: TYPE = RECORD [ proc: PROC[info: LarkInfo, clientData: REF], clientData: REF ]; RegisterTrunk: PROC[ hostSmartsID: Thrush.SmartsID, hostInfo: SmartsInfo, partyRname: Thrush.ROPE ] RETURNS [ nb: Thrush.NB, smartsID: Thrush.SmartsID ]; EnableSmarts: PROC[r: REF]; -- r is really a LarkInfo Deregister: PROC[r: REF]; FlashDone: PROC[r: REF]; LarkParseEvent: -- INTERNAL -- PROC[r: REF]; NoteNewState: PROC[cDesc: ConvDesc, convEvent: Thrush.ConvEvent]; ComputeConnection: PROC[cDesc: ConvDesc] RETURNS [pInfo: ThParty.PartyInfo _ NIL]; LarkProgress: PROC[ interface: ThSmartsRpcControl.InterfaceRecord, shh: SHHH, convEvent: Thrush.ConvEvent ]; LarkSubstitution: PROC[ interface: ThSmartsRpcControl.InterfaceRecord, shh: SHHH, convEvent: Thrush.ConvEvent, oldPartyID: Thrush.PartyID, newPartyID: Thrush.PartyID ]; LarkReportAction: PROC[ interface: ThSmartsRpcControl.InterfaceRecord, shh: SHHH, report: Thrush.ActionReport ]; LarkCheckIn: PROC[ interface: ThSmartsRpcControl.InterfaceRecord, shh: Thrush.SHHH, credentials: Thrush.Credentials, reason: Thrush.Reason, nextScheduledCheck: INT _ LAST[INT] ]; GetSmartsInfo: PROC[smartsID: Thrush.SmartsID] RETURNS [info: SmartsInfo]; GetSIC: PROC[info: SmartsInfo] RETURNS [ state: Thrush.StateInConv ]; ChangeState: PROC[ cDesc: ConvDesc, state: Thrush.StateInConv _ $idle, reason: Thrush.Reason _ NIL, -- $wontSay comment: Thrush.ROPE_NIL, bilateral: BOOL_FALSE -- See Thparty.Advance[...bilateral] ] RETURNS [nb: Thrush.NB]; -- advisory only, by this point ForgetConv: PROC[cDesc: ConvDesc]; GetConvDesc: PROC[info: SmartsInfo] RETURNS [ cDesc: ConvDesc_NIL ]; GetConv: PROC[info: SmartsInfo, -- ConvEvent, ActionReport, or SmartsInfo credentials: Thrush.Credentials, createOK: BOOL_FALSE] RETURNS [ cDesc: ConvDesc ]; HardwareInUse: PROC[cDesc: ConvDesc] RETURNS [inUse: BOOL]; HardwareRequired: PROC[cDesc: ConvDesc] RETURNS [required: BOOL]; DBInfo: PROC[partyID: Thrush.PartyID, attribute: ATOM_NIL, prevRNAtom: ATOM_NIL] RETURNS [ rName: Rope.ROPE, rNAtom: ATOM, value: Rope.ROPE ]; RegisterServiceProvider: PROC[ actionClass: Thrush.ActionClass, -- to prevent duplicates serviceProvider: PROC[credentials: Thrush.Credentials, smartsInfo: SmartsInfo] ]; EnterLarkState: PROC [ info: LarkInfo, newState: LarkState, data: LIST OF REF ANY_NIL ]; EnterLarkSt: PROC [ info: LarkInfo, newState: LarkState, data: LIST OF REF ANY_NIL ]; Fail: PROC[info: LarkInfo, reason: Rope.ROPE, informLark: BOOL_FALSE]; FailInt: PROC[info: LarkInfo, reason: Rope.ROPE, informLark: BOOL_FALSE]; -- Internal version QueueFeeps: PROC [ sInfo: SmartsInfo, feeps: Rope.ROPE ]; SetupTimeouts: PROC[info: LarkInfo, debugging: BOOL ]; Deb: PROC[info: LarkInfo, r: Rope.ROPE, p1, p2, p3, p4: IO.Value_[null[]]]; CheckHookState: PROC [ info: LarkInfo] RETURNS [ onHook: BOOL_TRUE ]; TonesDone: PROC[ info: LarkInfo, commandEvent: Lark.StatusEvent ]; QueueLarkAction: PROC[ info: LarkInfo, ref: REF ]; }. %ŒThSmartsPrivate.mesa Copyright Σ 1985, 1986, 1987 by Xerox Corporation. All rights reserved. Last modified by D. Swinehart, June 21, 1987 11:06:59 pm PDT Polle Zellweger (PTZ) August 29, 1985 5:35:30 pm PDT Last Edited by: Pier, May 3, 1984 1:04:49 pm PDT Copies Types States (enumerated types) and other scalars Parser is controlled by state sequence that's largely independent of the state of the smarts in any conversation. Parser represents the user's wishes. After parsing is complete, other processing determines whether these wishes can be granted. This state is essentially a superset of Thrush.StateInConv. It is used to express the user's wishes; when wish and reality coincide, it is set to the corresponding StateInConv, and quiescence follows, at least temporarily. Control of the Lark hardware state (remaining types) Encodes the progression of states of the telset switchhook (sh) and the speakerphone switch (sw) (which can progress from off to on, from on to off, or when on can be "clicked". The state machine is approximately: onhook => telset (sh on), speaker (sw click), sPEAKER (sw on) telset => onhook (sh off), monitor (sw click), mONITOR (sw on) speaker => onhook (sw click), sPEAKER (sw on), telset (sh on) sPEAKER => onhook (sw off), mONITOR (sh on) monitor => telset (sw click), speaker (sh off), mONITOR (sh on) mONITOR => telset (sw off), sPEAKER (sh off) There are some other transitions that shouldn't happen, but are treated in as harmless a way as possible when they do. Outside events can also cause SwitchState to revert to onhook, whatever the settings of the switches. In this situation, the assumption is that all switches are off; subsequent off transitions are ignored. no ring, glitch interval, in-a-ring, break Structures Information used by LarkSmarts and LarkTrunkSmarts implementations They require similar information, although the trunk does not use all of it. Trunk or station smarts, depending on which this is. State of Lark hardware, shared between Lark and Trunk Parsing control fields Allows Lark, Lark trunk, ... smarts to parse different command languages Command procedure to act on results of completely parsed command Procedure to update conversation description based on event: smarts-specific Independent of any notion of what's going on in eventInfo; desire of local user Input actions, registrations, and failure events are serialized on an MBQueue. Here are the REF types that carry the parameterization to the queued procedures. 1. Input events 2. Lark Failure -- just the LarkInfo 3. Registration -- see LarkSmartsInitImpl.Register Access to the Lark hardware via the Lark interface. This monitored record is shared by the Smarts info for both the LarkSmarts and LarkTrunkSmarts. There are also some random shared fields kept here. Some values that have to be preserved from one larkState to another Click and ring detect timings Lark reports the time when a ringing voltage is detected on the telewall, and the time when the voltage goes away. There can be an on-off glitch when the phone is hung up, and ringing is an alternating thing, so we need to interpret these signals before passing on to higher levels. See LarkInImpl. Ringing control information When a Note in a tune specifies "notify", expectedNotification is incremented (mod the lower-case letters) and sent along to the Lark. When the Lark finishes that note, it notifies the smarts, and eventually LarkOut, using that value. It's possible (though not desired) for this notification to precede the "WAIT" that pends notification. In this case, we mustn't wait. See LarkOutImpl.DoTones and ditto.WaitQ. receivedNotification is set to a value outside the range just after each WAIT opportunity terminates. LarkSupervisor Variables For use by LarkCall Registrants Limited registration for handling Lark-to-Server events for peripheral services, informing them of conversation termination, . . . See LarkInImpl, LarkOutImpl for usage discussions. There is increasing need for specifications, such as text-to-speech synthesis information and such, which needs to be communicated synchronously to the Lark, but which is too application-specific to be dealt with explicitly here. To achieve such a call, one issues EnterLarkState[...., sameState, [.... , LarkCall, ...]]. This will be queued for the Lark supervisor, which will invoke the LarkCall if the Lark is in one of the standard conversation states. It won't work during any of the tones states, failure states, idle state, etc. The callback proc should do very innocuous things, ultimately invoking info.interface.SomeLarkProc. Error recovery on failure is handled by the supervisor. *SmartsImpl Inter-module communication (including TrunkSmarts) Registration of Lark trunks (back doors) Called from LarkSmarts.Register to set up Party, Smarts, SmartsInfo for Trunk Lark is asserted ready to go. Tell the party, and make Lark operational. r is a larkInfo, really. Larks, their smarts, and their parties, can only be decommissioned by calling ThSmartsPrivate.Fail, which disassembles them from the bottom up. r is a larkInfo, really. Cause a report to be issued to the conversation in which this trunk is a party that switchhook flashing is complete. LarkAvailable: PROC[info: SmartsInfo] RETURNS [avail: BOOL];  Crowbar: obsolete. See LarkSmartsImpl.LarkAvailable. LarkSmartsInitImpl has to supply the stub version of these ThSmarts functions, implemented in LarkSmartsSupImpl, in an interface record. Return current state Try to locate a description for our involvement in the credentials.convID (may be nullConvID, where the purpose is to create a new, unassigned cDesc). If credentials includes a partyID, that's used, else we guess of what party represents us. If credentials contains a smartsID, we check to make sure it's us. Returns "Sturgis.pa" and $sturgis.pa, and if attribute is given, value _ the selected attribute for "Sturgis.pa" in the "color pages" database If prevRNAtom is supplied, partyID need not be used to identify party. Outboard Smarts services to Smarts Communications Smarts-to-LarkOut Procedures ENTRY version Put this lark into the indicated state, setting tones, crossbar, ethernet connections, whatever else is appropriate to the state. By this point, the higher levels are supposed to have sorted out any conflicts between the requirements of the two Smarts (Lark and LarkTrunk) that control the Lark. A single state may not be enough to do that, in the long run. Data is a list of (at this writing): Party.PartyInfo (containing connection specifications) Lark.KeyTable LarkPlay.toneSpec Thrush.ProseSpecs Atom.DottedPair (allows keyword values to be presented): $audioSource: [$lineA, $lineB, NIL ($telset)] $transmitOnly: [$TRUE, $FALSE] $phoneNumber: "number to dial" $textToSpeech: [$TRUE, $FALSE] The KeyTable should be accepted and forwarded on to the Lark whenever it appears, while the others will be interpreted relative to newState. Making everything a dotted pair would be less efficient but more uniform. INTERNAL version Cause Lark to fail and deregister attached smarts, parties. If informLark is TRUE and Lark is operational, take steps to cause Lark to boot and re-register. A number of timeout behaviors are different if the Lark is under development than if it is part of the operational system. Whether it's operational is determined by the database, properly the domain of Smarts-level code, but how to set the timeouts is the domain of the Lark-level code, thus this procedure to connect them together. Smarts-to-LarkIn Procedures Determines if user terminal appears to be offhook. May not be able to tell if there's a "click-mode" speakerphone call in progress. LarkIn-to-LarkOut Procedures INTERNAL version A way to feed back tone completions, initiated by LarkOut, back to LarkOut from LarkIn. Feep tones don't go through this path, since higher-levels need to know about the situation. If confident enough that it's OK to do it in the current state, can just queue for the Lark supervisor to issue. Swinehart, May 21, 1985 4:39:39 pm PDT Cedar 6.0, adding Text-to-speech service changes to: LarkInfoBody Polle Zellweger (PTZ) August 8, 1985 8:11:29 pm PDT changes to: pResetConfirmEnd, stopAndFlushEnd, incorrectClientMarker, flushMarker Polle Zellweger (PTZ) August 19, 1985 2:52:15 pm PDT Handle Prose flushing. changes to: pResetConfirmEnd, stopAndFlushEnd, incorrectClientMarker, flushMarker, LarkInfoBody (added flushJustFinished) Polle Zellweger (PTZ) August 20, 1985 7:50:19 pm PDT changes to: ResetProse, ProseControlDone, ReportProseDone Polle Zellweger (PTZ) August 29, 1985 5:31:56 pm PDT Place local variables from LarkOutImpl.LarkSupervisor into LarkInfo record. changes to: LarkInfoBody, maxClientMarker, indexMarkerEnd, maxControlMarker, pReset, pResetConfirmEnd, stopAndFlush, stopAndFlushEnd, flushMarker, proseFailure Swinehart, October 25, 1985 6:00:46 pm PDT Handle => ID changes to: DIRECTORY, ConversationID, PartyID, SmartsID, SmartsInfoBody, ConvDescBody, LarkInfoBody, RegisterTrunk, LarkProgress, LarkSetInterval, GetSmartsInfo, GetConv Swinehart, May 25, 1986 10:19:42 pm PDT Lark => LarkOps changes to: DIRECTORY, LarkInfoBody Swinehart, January 1, 1987 9:39:28 pm PST Still trying to get FD/BD conflict stuff right. Go back to doing it at the party level. changes to: LarkState, QueueLarkAction Swinehart, April 6, 1987 8:19:55 am PDT Cedar 7.0, NameDB changes changes to: DBInfo Swinehart, June 21, 1987 9:12:48 pm PDT Add LarkCheckIn changes to: LarkReportAction, LarkCheckIn Κ ,˜šœ™IcodešœH™HJšœ<™œœ˜ΐ—Jšœœ˜Jšœœ˜$Jšœ œ˜!J˜,J˜J˜—šœœ œ˜&J™—šΟc™J™Jšœœ œ˜Jšœ œ˜-J™—šž™J™™+J˜J™τšœ œ˜J˜S—J™J™ίJ˜Jšœ4™4šœ œ˜Jšœ ž˜Jšœ ž˜Jšœ ž&˜2Jšœž ˜Jšœž.˜=Jšœž>˜OJšœž(˜8Jšœ ž&˜2Jšœ ž2˜>Jšœ ž˜'Jšœ ž˜%Jšœ ž˜(Jšœ ž!˜.J˜—Jšœœ"˜5J˜šœ œ:˜K™ΦJ™=Jšœ>™>Jšœ=™=Jšœ+™+Jšœ?™?Jšœ,™,—JšœΖ™Ζ—J˜šœœ"˜4J™*—J˜Jšœœ˜#Jšœ œœž&˜@J˜Jšœž+˜IJšœ ž!˜AJ˜šœ œ˜JšœQ˜Q—šœœœ˜J˜ Jšœ˜Jš œœœœ œ˜.Jšœœ œœ˜7J˜—J™—™ J™JšœB™BJšœL™LJ˜Jšœ œœ˜&šœœ œ˜'J˜Jšœž˜8šœ-˜-Jšœ4™4—Jšœœž(˜I˜J™5—Jšœ!œ˜%Jšœœž3˜PJ™J™šΟn œœœž"˜=J™H—šŸœœœœ˜0J™@—šŸ œœ/œ˜FJ™L—J˜%˜J™O—Jšœœœ˜Jšœ œ˜Jšœœž2˜AJšœ$œ˜2J˜Jšœœ˜J˜J˜—™ ™Jšœœœ˜.šœœœ˜#J˜J˜.J˜——J™$J™2—J˜Jšœœœœ ˜+Jšœ œœ˜"šœœœ˜Jšœž3˜LJšœ#ž)˜LJšœ˜Jšœœœž*˜KJšœ-žO˜|J˜—J™Jšœ œœ˜(šœœœ˜ Jšœž˜"J˜,Jšœ ˜J˜—J˜—šœΙ™ΙJ™Jšœ œœ˜"šœœ œ˜%J˜Jšœ.ž'˜UJšœœž)˜4J˜-J˜2Jšœž.˜MJšœž$˜;J˜Jšœž6˜UJšœœœž8˜OJšœ œœžM˜fJš œ œœœœž4˜QJš œ œœœœž%˜BJšœ œœž˜+Jšœœœž˜:Jšœ  œž#˜J™šŸ œœ˜šœ(™(J™M—JšœHœ˜NJšœœ˜5—J˜šŸ œœœž˜5J™IJ™—šŸ œœœ˜J™©—J˜šŸ œœœ˜J™ŽJ™—šŸœžœœœ˜,J˜—JšŸ œœ/˜AJ˜JšŸœœœœ˜RJ˜šŸ œœœ œ™