<> <> <> <> DIRECTORY Atom USING [ DottedPair, DottedPairNode ], IO, Commander USING [ CommandProc, Register ], Convert USING [ RopeFromInt ], Lark USING [ bStar, bThorp, ConnectionSpec, ConnectionSpecRec, CommandEvent, CommandEvents, CommandEventSequence, Device, disabled, EchoParameters, EchoParameterRecord, enabled, endNum, Event, KeyTable, Milliseconds, o3i1, o2i2, o1i1, Passel, reset, SHHH, StatusEvent, Tone, ToneSpec, ToneSpecRec, VoiceBuffer ], LarkPlay USING [ ToneList, ToneSpec, ToneSpecRec ], LarkOpsRpcControl, LarkSmarts, List USING [ Nconc1 ], Multicast USING [ HandleMulticast, StopHandlingMulticast ], Nice, Process USING [ Detach, EnableAborts, MsecToTicks, SetTimeout ], Pup USING [ nullSocket ], Rope USING [ Cat, Concat, Fetch, FromChar, Length, ROPE, Substr, Translate, TranslatorType ], RPC USING [ CallFailed ], ThNet USING [ pd ], ThParty USING [ PartyInfo ], ThPartyPrivate USING [ SmartsData ], Thrush USING[ NetAddress, ProseSpec, ProseSpecs, ROPE, SHHH, SmartsID ], ThSmartsPrivate USING [ ConvDesc, flushMarker, proseFailure, indexMarkerEnd, LarkInfo, LarkProseQueue, LarkState, LSwitches, LState, maxClientMarker, maxControlMarker, ProgressTones, ProseCmd, SmartsInfo, SwitchState ], TU USING [ RefAddr ], VoiceUtils USING [ ProblemFR, Report ] ; LarkOutImpl: CEDAR MONITOR LOCKS info USING info: LarkInfo IMPORTS Commander, Convert, IO, LarkOpsRpcControl, List, Multicast, Nice, Process, Rope, RPC, ThNet, TU, VoiceUtils EXPORTS ThSmartsPrivate= { OPEN IO; <> ConvDesc: TYPE = ThSmartsPrivate.ConvDesc; LarkInfo: TYPE = ThSmartsPrivate.LarkInfo; LarkState: TYPE = ThSmartsPrivate.LarkState; SmartsData: TYPE = ThPartyPrivate.SmartsData; SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo; SmartsID: TYPE = Thrush.SmartsID; ProseCmd: TYPE = ThSmartsPrivate.ProseCmd; ROPE: TYPE = Thrush.ROPE; firstTone: LarkState = FIRST[ThSmartsPrivate.ProgressTones]; bStar: Lark.Event = Lark.bStar; bThorp: Lark.Event = Lark.bThorp; enabled: Lark.Event = Lark.enabled; endNum: Lark.Event = Lark.endNum; disabled: Lark.Event = Lark.disabled; reset: Lark.Event = Lark.reset; larkRegistry: ROPE _ ".Lark"; PD: TYPE = RECORD [ waitForTelco: CARDINAL _ 500, -- default values for initial pause, on time, and off time telcoMinOn: CARDINAL _ 60, -- when generating touch-tones. telcoMinOff: CARDINAL _ 60, flashWaitTime: CARDINAL _ 800, idleWaitTime: CARDINAL _ 20000, -- time for supervisor to wait for more events. blinkWaitTime: CARDINAL _ 500, -- if LED is blinking, don't wait so long. backDoorOH: BOOL_FALSE, callTimeoutOK: BOOL_FALSE, -- set to keep Thrush alive when debugging a Lark. tonesInvalid: BOOL_TRUE, tonesLast: BOOL_TRUE, -- sets up alternate lark setup situation in supervisor loop <<<>>> noisyFeeps: BOOL_FALSE -- TRUE if caller is to hear automatically-generated touchtones. ]; pd: REF PD _ NEW[PD_[]]; dialTone: LarkPlay.ToneSpec _ NIL; busyTone: LarkPlay.ToneSpec _ NIL; errorTone: LarkPlay.ToneSpec _ NIL; ringbackTone: LarkPlay.ToneSpec _ NIL; quenchSpec: Lark.ToneSpec _ NEW[Lark.ToneSpecRec _[volume: 0, totalTime: 0, tones: LIST[[0,0,0,0]]]]; <> pReset: PUBLIC ProseCmd _ "\022"; stopAndFlush: PUBLIC ProseCmd _ "\033[S"; commenceSpeech: ProseCmd = "\033[C"; -- \033 is ESC cmdLeader: ProseCmd = "\033["; -- for constructing arbitrary commands indexMarkerLen: INT = 6; <> minControlMarker: INT = 200; -- reserved for packet control <> speechDoneMarker: INT = 255; speechDone: ProseCmd = "\033[C\033[255i"; -- commence speech & report back when done <> EnterLarkState: PUBLIC ENTRY PROC[ info: LarkInfo, newState: LarkState, data: LIST OF REF ANY_NIL ] = { ENABLE UNWIND=>NULL; EnterLarkSt[info, newState, data]; }; EnterLarkSt: PUBLIC INTERNAL PROC[ info: LarkInfo, newState: LarkState, data: LIST OF REF ANY ] = { ENABLE UNWIND=>NULL; trans: LSTrans _ lsTrans[info.larkState][newState]; oldState: LarkState = info.larkState; sw: BOOL_FALSE; otherAction: REF_NIL; connectionSpec: ThParty.PartyInfo; toneSpec: LarkPlay.ToneSpec; newProses: Thrush.ProseSpecs; ropeSpec: Rope.ROPE; keyTable: Lark.KeyTable; feepSpecs: REF AFeepType_NIL; IF pd.tonesInvalid THEN SetTones[]; FOR dL: LIST OF REF ANY_data, dL.rest WHILE dL#NIL DO WITH dL.first SELECT FROM cS: ThParty.PartyInfo => connectionSpec _ cS; tS: LarkPlay.ToneSpec => toneSpec _ tS; nP: Thrush.ProseSpecs => newProses _ nP; kT: Lark.KeyTable => keyTable _ info.keyTable _ kT; dP: Atom.DottedPair => SELECT dP.key FROM $audioSource => {info.audioSource _ NARROW[dP.val]; sw_TRUE; }; $transmitOnly => {info.transmitOnly _ dP.val=$true;sw_TRUE; }; $textToSpeech => info.textToSpeech _ dP.val=$true; $phoneNumber => ropeSpec _ NARROW[dP.val]; ENDCASE; -- unknown ENDCASE; -- unknown ENDLOOP; IF connectionSpec # NIL AND connectionSpec.numParties=2 THEN TRUSTED { info.forwardedCall _ connectionSpec[0].socket.host # connectionSpec[1].socket.host; IF info.blinkProcess=NIL THEN Process.Detach[info.larkProcess _ FORK BlinkLED[info]]; }; <> <> SELECT trans FROM nop => NULL; -- Certifiably nothing at all to do, unless there's data or some submode has changed. watch out set => { info.larkState_newState; RETURN; }; X => {info.audioSource _ NIL; info.transmitOnly _ FALSE;LarkProblem["%g: Invalid LarkState Transition", info]; RETURN;}; rec => { info.larkState_recovering; LarkFailed[info.larkSmartsInfo]; --RETURN--}; fai => { info.larkState _ failed; LarkProblem["%g: Lark failure requested by server", info]; info.larkProcess _ NIL; info.audioSource _ NIL; info.transmitOnly _ FALSE; NOTIFY info.stateChange; -- Be sure process notices failure and disappears. RETURN; }; zap => { info.audioSource _ NIL; info.transmitOnly _ FALSE; }; ENDCASE; IF tSetFwd[trans] = setFwd THEN { <> newState _ IF info.forwardedCall THEN trunkForwarding ELSE trunkTalking; trans _ lsTrans[info.larkState][newState]; }; info.larkState_newState; <> <> IF (tDisconn[trans] = $disconnect OR connectionSpec#NIL) AND info.spec#NIL THEN { <> IF ThNet.pd.debug THEN Deb[ info, 'd ]; QueueLarkAction[info, aDisconnect]; }; <