DIRECTORY IO USING [ STREAM ], Lark USING [ CommandEvents, ConnectionSpec, disabled, enabled, Event, KeyTable, LarkModel, o3i1, StatusEvent, ToneSpec, ts0, ts12 ], LarkPlay USING [ ToneList, ToneSpec ], LarkOpsRpcControl USING [ InterfaceRecord ], MBQueue USING [ Queue ], Rope USING [ROPE], BasicTime USING [ GMT ], Thrush USING [ ConversationID, ConvEvent, ConvEventBody, NB, NetAddress, nullID, nullConvID, PartyID, PartyType, ProseSpec, ProseSpecs, Reason, ROPE, SHHH, SmartsID, StateInConv ], ThParty USING [ PartyInfo ], ThPartyPrivate USING [ SmartsData ], 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 failed, -- This Lark has died and its brain is dying, too. recovering, -- Lark is presumed not to work, but use attempts don't raise ERRORS 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, currentConvID: Thrush.ConversationID_Thrush.nullConvID, -- the one we're dealing with. requests: MBQueue.Queue_NIL, -- serialize progress reports, requests for actions ParseEvent: PROC[smartsInfo: SmartsInfo, sEvent: Lark.StatusEvent], 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 ]; 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 ]; ConvRequest: TYPE = REF ConvRequestBody; ConvRequestBody: TYPE = RECORD [ cDesc: ConvDesc, -- present state, desiredSituation: Thrush.ConvEventBody _ [] ]; 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? -- debugIn: IO.STREAM, debugPrint: IO.STREAM_NIL, larkState: LarkState _ $none, -- tone/crossbar/connect state of actual Lark hardware 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 audioSource: AudioSource _ NIL, -- e.g., $telset switchState: SwitchState _ $onhook, -- state of switchhook/speakerphone switch... textToSpeech: BOOL_FALSE, -- Prose 2000 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, spec: ThParty.PartyInfo_NIL, cSpec: Lark.ConnectionSpec_NIL, keyTable: Lark.KeyTable _ NIL, toneSpec: LarkPlay.ToneSpec_NIL, nextToneList: LIST OF LarkPlay.ToneList_NIL, larkToneSpec: Lark.ToneSpec_NIL, proseResponse: Rope.ROPE_NIL, -- holds incomplete Prose responses flushJustFinished: BOOL_FALSE, -- can expect to have to flush proseQueue next time thru LarkInImpl.HandleProseOutput proseQueue: LarkProseQueue_NIL, -- holds queue of client markers and proseSpecs pTail: LarkProseQueue_NIL, textToSpeak: Rope.ROPE_NIL, clientMarker: INT_maxClientMarker, controlMarker: INT_maxControlMarker, ctrlMarkerQueue: LIST OF REF ANY_NIL, -- holds queue of control markers pktsOutstanding: INT_0, flushInProgress: BOOL_FALSE, -- consider combining w flushJustFinished? 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 ]; LarkProseQueue: TYPE = LIST OF LarkProseSpecBody; LarkProseSpecBody: TYPE = RECORD [ proseSpec: Thrush.ProseSpec_NIL, proseMarker: INT_0 ]; ProseCmd: TYPE = Rope.ROPE; indexMarkerEnd: CHAR = 'i; maxClientMarker: INT = 199; maxControlMarker: INT = 250; pReset: ProseCmd; -- = "\022" (ControlR) pResetConfirmEnd: CHAR = 'R; stopAndFlush: ProseCmd; -- = "\033[S" (\033 is ESC) stopAndFlushEnd: CHAR = 'S; flushMarker: INT = 1000; proseFailure: INT = 1001; EnterLarkState: PROC [ info: LarkInfo, newState: LarkState, data: LIST OF REF ANY_NIL ]; EnterLarkSt: PROC [ info: LarkInfo, newState: LarkState, data: LIST OF REF ANY_NIL ]; TonesDone: PROC[ info: LarkInfo, commandEvent: Lark.StatusEvent ]; QueueFeeps: PROC [ sInfo: SmartsInfo, feeps: Rope.ROPE ]; ProseControlDone: PROC[info: LarkInfo, marker: INT]; ReportProseDone: PROC[info: SmartsInfo, proseSpec: Thrush.ProseSpec]; InterpretHookState: PROC [ info: LarkInfo, rawEvent: Lark.StatusEvent, sInfo: SmartsInfo ] RETURNS [ processedEvent: Lark.StatusEvent ]; CheckHookState: PROC [ info: LarkInfo] RETURNS [ onHook: BOOL_TRUE ]; RegisterTrunk: PROC[ hostSmartsID: Thrush.SmartsID, hostInfo: SmartsInfo, partyRname: Thrush.ROPE ] RETURNS [ nb: Thrush.NB, smartsID: Thrush.SmartsID ]; EnableSmarts: PROC[info: SmartsInfo] RETURNS[enabled: BOOL]; Deregister: PROC[smartsID: Thrush.SmartsID]; LarkParseEvent: -- INTERNAL -- PROC[smartsInfo: SmartsInfo, sEvent: Lark.StatusEvent]; 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 ]; LarkFailed: ERROR[sInfo: SmartsInfo]; 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 ] RETURNS [nb: Thrush.NB]; -- advisory only, by this point AssessDamage: PROC [nb: Thrush.NB, cDesc: ConvDesc, convEvent: Thrush.ConvEvent]; ForgetConv: PROC[cDesc: ConvDesc]; GetConvDesc: PROC[info: SmartsInfo] RETURNS [ cDesc: ConvDesc_NIL ]; GetConv: PROC[info: SmartsInfo, convID: Thrush.ConversationID, createOK: BOOL_FALSE] RETURNS [ cDesc: ConvDesc ]; DBInfo: PROC[partyID: Thrush.PartyID, attribute: ATOM_NIL, prevDbAtom: ATOM_NIL] RETURNS [ dbRname: Rope.ROPE, dbAtom: ATOM, value: Rope.ROPE ]; }. ThSmartsPrivate.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Last modified by D. Swinehart, May 31, 1986 4:03:15 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 Temporarily out of service -- please use the circular stairway newIntervals: Thrush.IntervalSpecs _ NIL, iTail: Thrush.IntervalSpecs _ NIL, desiredIntID: Thrush.IntID _ Thrush.nullIntID, newProses: Thrush.ProseSpecs _ NIL, pTail: Thrush.ProseSpecs _ NIL, desiredProseID: Thrush.IntID _ Thrush.nullIntID, originator: Orig _ $unknown, newSpec, newKeys, newAddress: BOOL _FALSE, newEvent: BOOL_FALSE, signallingStarted: BOOL_FALSE, 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 Prose control values 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 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 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. Reports low-level control marker completion from Prose (thru LarkInImpl) to LarkOutImpl, to trigger sending more text if there is any. For Prose metering only (to avoid filling Lark and Prose buffers). Reports client-level marker completion from Prose (thru LarkInImpl) to party level, for conversation mgmt and client completion reports. Corresponds to the end of a Finch client SpeakText command. Determines if user terminal appears to be offhook. May not be able to tell if there's a "click-mode" speakerphone call in progress. Registration of Lark trunks (back doors) Called from LarkSmarts.Register to set up Party, Smarts, SmartsInfo for Trunk Find out if the Lark is ready to go (i.e.., on-hook), then enable the corresponding party to allow this Lark to participate in the system. smartsID must describe a $telephone or $service smarts. Disables LarkOut communications and destroys all data structures (extrinsic and intrinsic) associated with this Smarts, both at the LarkSmarts and Party level. Also deregisters any associated Trunk. LarkSmartsInitImpl has to supply the stub version of these ThSmarts functions, implemented in LarkSmartsSupImpl, in an interface record. LarkSetInterval: PROC[ shh: SHHH, smartsID: Thrush.SmartsID, tune: Thrush.Tune, interval: Thrush.VoiceInterval, direction: Thrush.VoiceDirection, queueIt: BOOLEAN ] RETURNS [ d: Thrush.Disposition, u: Thrush.Tune ]; Return current state Converts from "Sturgis.pa" to "Sturgis.pa.lark", produces $sturgis.pa as well, and if attribute is given, value _ the selected attribute for "Sturgis.pa.lark" in the GV database If prevDBAtom is supplied, partyID need not be used to identify party. 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 Κ U˜šœ™Icodešœ Οmœ7™BJšœ:™:K™4J™0—J˜šΟk ˜ Jšžœžœžœ˜šœžœ˜ Jšœw˜w—Jšœ žœ˜&Jšœžœ˜,Jšœžœ ˜Jšœžœžœ˜Jšœ žœžœ˜šœžœ˜Jšœ*žœUžœžœ˜₯—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šœ Ÿ2˜=JšœŸD˜RJšœ Ÿ&˜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šœ8Ÿ˜VJšœžœŸ3˜PJ™J™šΟn œžœ3˜CJ™H—š œžœžœžœ˜0J™@—š  œžœ/žœ˜FJ™L—J˜%˜J™O—Jšœžœžœ˜Jšœ žœ˜JšœžœŸ2˜AJšœ$žœž˜1J˜—J˜Jšœžœžœžœ ˜+Jšœ žœžœ˜"šœžœžœ˜JšœŸ3˜LJšœ#Ÿ)˜LJšœž˜J˜J™?Jšœ%žœ™)Jšœžœ™"J™.Jšœžœ™#Jšœžœ™J™0J™Jšœžœž™*Jšœ žœžœ™Jšœžœžœ™—J™Jšœ žœžœ˜(šœžœžœ˜ JšœŸ˜"J˜+J˜—J˜—šœΙ™ΙJ™Jšœ žœžœ˜"šœžœž œž˜%J˜Jšœ.Ÿ'˜UJšœžœŸ)˜4J˜-J˜2JšœŸ.˜MJšœŸ$˜;Jš œ žœžœžœžœžœ˜/J˜JšœŸ6˜UJš œ žœžœžœžœŸ4˜QJš œ žœžœžœžœŸ%˜BJšœ žœžœŸ˜+JšœžœžœŸ˜:Jšœ ž œŸ#˜