<> <> <> <> DIRECTORY BasicTime USING [ Update, Now, Period ], IO, Lark USING [ bStar, bThorp, ConnectionSpec, CommandEvent, CommandEvents, CommandEventSequence, Device, disabled, EchoParameters, EchoParameterRecord, enabled, endNum, Event, Hertz, KeyTable, Milliseconds, o3i1, o2i2, o1i1, Passel, reset, SHHH ], LarkSmarts, Log USING [ ProblemFR, Report, SLOG ], Nice, PlayOps USING [ PlayString, BeepProc ], Process USING [ Detach, EnableAborts, MsecToTicks, SetTimeout ], Rope USING [ Fetch, Length, ROPE ], RPC USING [ CallFailed ], ThNet USING [ pd ], ThPartyPrivate USING [ SmartsData ], Thrush USING[ H, pERROR, ROPE, SHHH, SmartsHandle, ThHandle ], ThSmartsPrivate USING [ ConvDesc, GetConvDesc, HookState, LarkInfo, LarkState, LarkStateSpec, LSwitches, LState, Note, ProgressTones, RingMode, RingEnable, SetStdRingInfo, SmartsInfo, TerminalType, ToneSpec, ToneSpecRec ], TU USING [ RefAddr ] ; LarkOutImpl: CEDAR MONITOR LOCKS info USING info: LarkInfo IMPORTS BasicTime, IO, Log, Nice, PlayOps, Process, Rope, RPC, ThNet, Thrush, ThSmartsPrivate, TU EXPORTS ThSmartsPrivate= { OPEN IO; <> ConvDesc: TYPE = ThSmartsPrivate.ConvDesc; H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; }; LarkInfo: TYPE = ThSmartsPrivate.LarkInfo; LarkState: TYPE = ThSmartsPrivate.LarkState; SmartsData: TYPE = ThPartyPrivate.SmartsData; SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo; SmartsHandle: TYPE = Thrush.SmartsHandle; TerminalType: TYPE = ThSmartsPrivate.TerminalType; 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, telcoMinOn: CARDINAL _ 60, telcoMinOff: CARDINAL _ 60, backDoorOH: BOOL_FALSE, echoControl: BOOL_TRUE, autoGVUpdate: BOOL_FALSE, -- If FALSE, operator must manually update true GV database. tonesLast: BOOL_FALSE, -- sets up alternate lark setup situation in supervisor loop ringsInvalid: BOOL_TRUE, -- set to cause recreation of standard ring tunes tonesVolume: CARDINAL _ 2, defaultRingVolume: CARDINAL _ 2, subduedVolumeInterval: CARDINAL_1, feepVolume: CARDINAL _ 0 ]; pd: REF PD _ NEW[PD_[]]; callTimeoutOK: BOOL_FALSE; -- set to keep Thrush alive when debugging a Lark. ToneSpec: TYPE = ThSmartsPrivate.ToneSpec; ToneSpecRec: TYPE = ThSmartsPrivate.ToneSpecRec; Note: TYPE = ThSmartsPrivate.Note; <> LSwitches: TYPE = ThSmartsPrivate.LSwitches; LState: TYPE = ThSmartsPrivate.LState; lDevs: ARRAY LSwitches OF Lark.Device = [ crossBar, offHookRelay, aRelay, sideTone, ringEnable, revertRelay, revertHookswitch, led, spMode, crossBar--random...not used-- ]; lStateForLetter: ARRAY CHAR['A..'Z] OF LSwitches = [ none, none, none, none, none, -- A to E revert, revertHook, hook, aSwitch, hook, none, led, -- F to L none, none, none, none, none, -- M to Q ringO, sideTone, spMode, none, none, none, none, none, -- R to Y xBarAll -- Z -- ]; LSTrans: TYPE = { nop, -- nothing to do set, -- enter specified state (usu. step to recovery) without taking any other actions. zap, zpu, -- reset Lark hardware (u means unconnect first) trk, tkn, -- Set for electronic phone connection (n means silence tones first) frd, frn, -- Trunk-to-network forwarding versions of trk, tkn (frn probably doesn't exist; wrong end <>) tlk, -- like supervision, but must also adjust switching. sup, spn, -- supervision, OK to change connection, key table. (n means silence tones first) ksp, -- key supervision, OK to change key table. sgl, sgn, -- Do trunk signalling (n means silence tones first) fls, -- Flash the phone line rng, rgu, -- Set for ringing (u means unconnect first, r means repeating tone) dia, diu, -- Set for dial tone (tones should be more generic and user-programmable than this!) rbk, rbu, -- Set for ring back bzy, bzu, -- Set for busy tone err, eru, -- Set for error tone sil, -- silence tones, ksp obtains fai, -- enter failed state, by Smarts-level request. Don't complain, just do it. Make sure process goes away. rec, -- move from failed state to recovering state, but complain to caller that Lark has failed, via signal. X -- invalid transition; complain, then remain in present state (go idle?) }; lsTrans: ARRAY LarkState OF ARRAY LarkState OF LSTrans = [[ <> nop, zap, X, X, X, X, X, X, X, X, X, X, X, X, X ],[-- non (none) X, nop, spn, sgl, trk, frd, X, fai, X, rng, nop, dia, rbk, bzy, err ],[-- idl (idle) X, zpu, sup, X, X, X, X, fai, X, rgu, nop, diu, rbu, bzu, eru ],[-- tlk (talking) X, zap, X, ksp, trk, frd, X, fai, X, X, nop, X, X, X, X ],[-- sig (trkSignalling) X, zap, X, X, ksp, X, fls, fai, X, X, nop, X, X, X, X ],[-- trk (trkTalking) X, zpu, X, X, X, sup, X, fai, X, X, nop, diu, rbu, bzu, eru ],[-- fwd (trkForwarding) X, zap, X, X, trk, X, sup, fai, X, X, nop, X, X, X, X ],[-- fls (trkFlash) set, rec, rec, rec, rec, rec, rec, set, set, rec, rec, rec, rec, rec, rec ],[-- fai (failed) set, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop ],[-- rec (recovering) X, zap, spn, sgn, tkn, frn, X, fai, X, ksp, sil, dia, rbk, bzy, err ],[-- rng (ringing) X, zap, tlk, sgl, trk, frd, X, fai, X, rng, ksp, dia, rbk, bzy, err ],[-- shh (silence) X, zap, spn, sgn, tkn, frn, X, fai, X, rng, sil, ksp, rbk, bzy, err ],[-- dia (dialTone) X, zap, spn, sgn, tkn, frn, X, fai, X, rng, sil, dia, ksp, bzy, err ],[-- rbk (ringBack) X, zap, spn, sgn, tkn, frn, X, fai, X, rng, sil, dia, rbk, ksp, err ],[-- bzy (busyTone) X, zap, spn, sgn, tkn, frn, X, fai, X, rng, sil, dia, rbk, bzy, ksp ] -- err (errorTone) ]; <> TDisconn: TYPE = { X, disconnect }; tDisconn: ARRAY LSTrans OF TDisconn = [ -- zpu, rgu, diu, rbu, bzu, eru X, X, X, disconnect, X, X, X, X, X, X, X, X, X, X, X, X, disconnect, X, disconnect, X, disconnect, X, disconnect, X, disconnect, X, X, X, X ]; TDoTones: TYPE = { X, doTones, stopTones }; tDoTones: ARRAY LSTrans OF TDoTones = [ -- rng, rgu, dia, diu, rbk, rbu, bzy, bzu, err, eru; tkn, spn, sgn, sil X, X, X, X, X, stopTones, X, X, X, X, stopTones, X, X, stopTones, X, doTones, doTones, doTones, doTones, doTones, doTones, doTones, doTones, doTones, doTones, stopTones, X, X, X ]; THookState: TYPE = { X, reset, spkrTrans }; tHookState: ARRAY LSTrans OF THookState = [ -- zap, zpu; trk, tkn, tlk, spn, fls, dia, diu, rbk, rbu, bzy, bzu, err, eru, sil X, X, reset, reset, spkrTrans, spkrTrans, X, X, spkrTrans, X, spkrTrans, X, X, X, spkrTrans, X, X, spkrTrans, spkrTrans, spkrTrans, spkrTrans, spkrTrans, spkrTrans, spkrTrans, spkrTrans, spkrTrans, X, X, X ]; TSwitch: TYPE = { X, switch, switchIfDiff }; tSwitch: ARRAY LSTrans OF TSwitch = [-- zap, zpu, trk, tkn, frd, frn, tlk, spn, sgl, sgn, fls; rng, rgu, dia, diu, rbk, rbu, bzy, bzu, err, eru X, X, switch, switch, switch, switch, switch, switch, switch, X, switch, X, switch, switch, switch, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switch, X, X, X ]; TSetKey: TYPE = { X, setKey }; tSetKey: ARRAY LSTrans OF TSetKey = [ -- trk, tkn, frd, frn, tlk, sup, spn, ksp, sgl, sgn, fls, rng, rgu, dia, diu, rbk, rbu, bzy, bzu, err, eru, sil X, X, X, X, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, setKey, X, X, X ]; <> ADisconnectType: TYPE = { aDisconnect }; aDisconnect: REF ADisconnectType _ NEW[ADisconnectType_aDisconnect]; ANoTonesType: TYPE = { aNoTones }; aNoTones: REF ANoTonesType _ NEW[ANoTonesType_aNoTones]; AFlashWaitType: TYPE = { aFlashWait }; aFlashWait: REF AFlashWaitType _ NEW[AFlashWaitType_aFlashWait]; <> <<>> dialTone: ToneSpec _ NIL; busyTone: ToneSpec _ NIL; errorTone: ToneSpec _ NIL; ringbackTone: ToneSpec _ NIL; ringTone: ToneSpec _ NIL; subduedRingTone: ToneSpec _ NIL; <> SetRingingParameters: PUBLIC ENTRY PROC[ info: LarkInfo, ringMode: ThSmartsPrivate.RingMode_internal, ringEnable: ThSmartsPrivate.RingEnable_on, ringDo: BOOL_FALSE, ringVolume: CARDINAL_pd.defaultRingVolume, ringInterval: INT_NULL, -- Seconds to disable ringTune: ROPE -- a PlayTune to be played when normal ringing is enabled. See Play.df for documentation ] = { ENABLE UNWIND=>NULL; changeEnable: BOOL; IF pd.ringsInvalid THEN { pd.ringsInvalid _ FALSE; dialTone _ NEW[ToneSpecRec _ [oneRing: FALSE, volume: pd.tonesVolume, totalTime: 10000, notes: LIST[[f1: 350, f2: 440, on: 5000, off: 0, repetitions: 2]]]]; busyTone _ NEW[ToneSpecRec _ [oneRing: FALSE, volume: pd.tonesVolume, totalTime: 10000, notes: LIST[[f1: 480, f2: 620, on: 500, off: 500, repetitions: 10]]]]; errorTone _ NEW[ToneSpecRec _ [oneRing: FALSE, volume: pd.tonesVolume, totalTime: 10000, notes: LIST[[f1: 480, f2: 620, on: 250, off: 250, repetitions: 20]]]]; ringbackTone _ NEW[ToneSpecRec _ [oneRing: FALSE, volume: pd.tonesVolume, totalTime: 12000, notes: LIST[[f1: 440, f2: 480, on: 2000, off: 4000, repetitions: 2]]]]; ringTone _ NEW[ToneSpecRec _ [oneRing: FALSE, volume: pd.defaultRingVolume, totalTime: 12000, notes: LIST[[f1: 440, f2: 480, on: 2000, off: 4000, repetitions: 2]]]]; subduedRingTone _ NEW[ToneSpecRec _ [ oneRing: TRUE, volume: pd.defaultRingVolume+pd.subduedVolumeInterval, totalTime: 500, notes: LIST[[f1: 440, f2: 480, on: 500, off: 0, repetitions: 1]] ]]; }; IF info=NIL THEN RETURN; changeEnable _ ringEnable#info.ringEnable; info.ringMode _ ringMode; info.ringEnable _ ringEnable; info.ringDo _ ringDo; info.ringVolume _ ringVolume; info.ringTuneRope _ ringTune; [] _ PrepareRingTune[info]; info.ringTime _ BasicTime.Update[BasicTime.Now[], ringInterval]; <> IF ~changeEnable THEN RETURN; SELECT ringEnable FROM on, subdued, off => NULL; ENDCASE => RETURN; info.defaultRingEnable _ ringEnable; ThSmartsPrivate.SetStdRingInfo[info, pd.autoGVUpdate]; }; EnterLarkState: PUBLIC ENTRY PROC[ info: LarkInfo, newState: LarkState, sInfo: SmartsInfo ] = { ENABLE UNWIND=>NULL; EnterLarkSt[info, newState, sInfo]; }; EnterLarkSt: PUBLIC INTERNAL PROC[ info: LarkInfo, newState: LarkState, sInfo: SmartsInfo ]={ ENABLE UNWIND=>NULL; newSpec: LIST OF ThSmartsPrivate.LarkStateSpec = LIST[[newState, sInfo]]; trans: LSTrans _ lsTrans[info.larkState][newState]; oldState: LarkState = info.larkState; cDesc: ConvDesc_NIL; keyTable: Lark.KeyTable; spec: Lark.ConnectionSpec; sw: BOOL_FALSE; echoAction: REF_NIL; ringTune: ToneSpec _ NIL; <> SELECT trans FROM nop => RETURN; -- Certifiably nothing at all to do, or inappropriate time to do it. set => { info.larkState_newState; RETURN; }; X => { LarkProblem["%g: Invalid LarkState Transition", sInfo]; RETURN; }; rec => { info.larkState_recovering; LarkFailed[sInfo]; --RETURN--}; fai => { info.larkState _ failed; LarkProblem["%g: Lark failure requested by server", sInfo]; info.larkProcess _ NIL; NOTIFY info.stateChange; -- Be sure process notices failure and disappears. RETURN; }; ENDCASE; info.larkState_newState; IF sInfo#NIL THEN cDesc _ ThSmartsPrivate.GetConvDesc[sInfo]; IF cDesc#NIL THEN { IF cDesc.newKeys THEN keyTable _ cDesc.cState.keyTable; IF cDesc.newSpec THEN spec _ cDesc.cState.spec; }; <> <> SELECT tDisconn[trans] FROM disconnect => { <> IF ThNet.pd.debug THEN Deb[ info, 'd ]; QueueLarkAction[info, aDisconnect]; }; ENDCASE; <