LarkOutImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Polle Zellweger (PTZ) November 4, 1985 8:42:01 pm PST
Last modified by D. Swinehart, November 24, 1986 8:06:52 pm PST
DIRECTORY
Atom USING [ DottedPair, DottedPairNode ],
IO,
Commander USING [ CommandProc, Register ],
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 ],
LarkOps USING [ LarkParameters, LarkParametersRec ],
LarkPlay USING [ ToneList, ToneSpec, ToneSpecRec ],
LarkOpsRpcControl,
LarkSmarts,
Multicast USING [ HandleMulticast, StopHandlingMulticast ],
Nice,
Process USING [ Detach, EnableAborts, MsecToTicks, SetTimeout ],
Pup USING [ nullSocket ],
Rope USING [ Fetch, Length, ROPE ],
RPC USING [ CallFailed ],
RPCTimeouts USING [ SetMaxTransmissions ],
ThNet USING [ pd ],
ThParty USING [ PartyInfo ],
ThPartyPrivate USING [ SmartsData ],
Thrush USING[ NetAddress, ROPE, SHHH, SmartsID ],
ThSmartsPrivate USING [
ConvDesc, LarkCall, LarkInfo, LarkState, LSwitches, LState, ProgressTones, SmartsInfo, SwitchState ],
TU USING [ RefAddr ],
VoiceUtils USING [ ProblemFR, Report ]
;
LarkOutImpl: CEDAR MONITOR LOCKS info USING info: LarkInfo
IMPORTS
Commander, IO, LarkOpsRpcControl, Multicast, Nice, Process, Rope, RPC, RPCTimeouts, ThNet, TU, VoiceUtils
EXPORTS ThSmartsPrivate= {
OPEN IO;
Declarations
ConvDesc: TYPE = ThSmartsPrivate.ConvDesc;
LarkInfo: TYPE = ThSmartsPrivate.LarkInfo;
LarkState: TYPE = ThSmartsPrivate.LarkState;
SmartsData: TYPE = ThPartyPrivate.SmartsData;
SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo;
SmartsID: TYPE = Thrush.SmartsID;
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";
TimeoutPolicy: TYPE = { never, always, unlessDebugging};
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.
keySynchTime: CARDINAL ← 3000, -- time for keys to be distributed, else give up
blinkWaitTime: CARDINAL ← 500, -- if LED is blinking, don't wait so long.
backDoorOH: BOOLFALSE,
toLarkTimeoutOK: TimeoutPolicy ← unlessDebugging,
Whether to let RPC calls from server to Lark time out. The default is to do so iff the database indicates the Lark is not in operational mode.
toLarkTimeoutTransmissions: CARDINAL ← 4, -- How long to give a lark to respond
fromLarkTimeoutOK: TimeoutPolicy ← unlessDebugging,
Determines what to tell the Lark to do about server timeouts.
fromLarkTimeoutTransmissions: CARDINAL ← 5, -- how long to give the server.
larkEventTimer: CARDINAL ← 6000,
larkTimeoutEvents: TimeoutPolicy ← unlessDebugging,
tonesInvalid: BOOLTRUE,
noisyFeeps: BOOLFALSE -- TRUE if caller is to hear automatically-generated touchtones.
];
pd: REF PDNEW[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]]]];
External Procedures
EnterLarkState: PUBLIC ENTRY PROC[
info: LarkInfo, newState: LarkState, data: LIST OF REF ANYNIL ] = {
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: BOOLFALSE;
otherAction: REFNIL;
connectionSpec: ThParty.PartyInfo;
toneSpec: LarkPlay.ToneSpec;
ropeSpec: Rope.ROPE;
keyTable: Lark.KeyTable;
feepSpecs: REF AFeepType←NIL;
keyTablesToDate: INT;
larkCall: ThSmartsPrivate.LarkCall ← NIL; -- See ThSmartsPrivate.LarkCall
IF pd.tonesInvalid THEN SetTones[];
FOR dL: LIST OF REF ANY�ta, dL.rest WHILE dL#NIL DO
WITH dL.first SELECT FROM
cS: ThParty.PartyInfo => connectionSpec ← cS;
tS: LarkPlay.ToneSpec => toneSpec ← tS;
kT: Lark.KeyTable => keyTable ← kT;
lC: ThSmartsPrivate.LarkCall => larkCall ← lC; -- see ThSmartsPrivate.LarkCall
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 info.forwardedCall THEN TRUSTED {
IF info.blinkProcess=NIL THEN Process.Detach[info.blinkProcess ← FORK BlinkLED[info]];
};
Relevant only for trunk calls. The hosts are different, so the local trunk is communicating to a remote Etherphone. See LarkSmartsSupImpl for more discussion of these connections. We don't handle conferences involving trunks, thus the numParties=2 test. Higher level code assures this. In this state, the LED flashes to let the user know why the switch hook and attempts to place calls don't work.
Each select statement combines cases to execute a subset of the required actions efficiently.
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.keyTablesDistributed ← info.keyTableDistrsRequested𡤀
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 {
If trunkTalking was requested, we must enter either trunkTalking or trunkForwarding, depending on whether the other end of the connection is on the same machine.
newState ← IF info.forwardedCall THEN trunkForwarding ELSE trunkTalking;
trans ← lsTrans[info.larkState][newState];
};
info.larkState←newState;
When leaving talking state but not going idle, must explicitly take down Ethernet connection.
Does this ever happen?
IF (tDisconn[trans] = $disconnect OR connectionSpec#NIL) AND info.spec#NIL THEN {
Queue up request to eliminate connections.
IF ThNet.pd.debug THEN Deb[ info, 'd ];
QueueLarkAction[info, aDisconnect];
};
Select tone/tune specifications.
toneSpec ← SELECT trans FROM
dia, diu => dialTone, -- to handset receiver
rbk, rbu => IF toneSpec#NIL THEN toneSpec ELSE ringbackTone,
bzy, bzu => busyTone,
err, eru => errorTone,
rng, rgu => toneSpec,
ENDCASE => NIL
;
SELECT tDoTones[trans] FROM
doTones => {
IF ThNet.pd.debug THEN Deb[ info, 'T ];
IF toneSpec#NIL THEN QueueLarkAction[info, toneSpec];
};
stopTones => { IF ThNet.pd.debug THEN Deb[ info, 't ]; QueueLarkAction[info, aNoTones]; };
ENDCASE;
Go offhook and enter speakerphone mode if noises need to be heard and phone isn't offhook
Go back onhook when idling from spkr (not sPkr) or monitor mode.
SELECT tHookState[trans] FROM
reset => {
SELECT info.switchState FROM
$monitor, $speaker => info.switchState←$onhook; -- going totally idle
ENDCASE;
};
spkrTrans => IF info.switchState=$onhook THEN -- dialtone, direct connect or ringback
info.switchState ← $speaker;
ENDCASE; -- no state change cases.
IF info.switchState#info.lastSwitchState THEN sw←TRUE;
SELECT tSwitch[trans] FROM
switch => sw←TRUE;
switchIfDiff => IF oldState<firstTone OR newState<firstTone THEN sw←TRUE;
ENDCASE;
SELECT trans FROM
sgl, sgn => {
IF ThNet.pd.debug THEN Deb[info, 'F];
feepSpecs ← RopeToDTMF[ropeSpec];
pd.noisyFeeps ← feepSpecs.audible;
};
ENDCASE;
IF sw THEN TRUSTED {
command: ROPE ← larkCommands[info.switchState][newState];
IF ThNet.pd.debug THEN Deb[info, 'M, rope[command]];
otherAction ← QueueCommandSequence[info, command, @info.lState, info.scratchEv];
IF trans=fls THEN {
Process.Detach[FORK FlashWait[info]];
info.larkState ← oldState; -- never really enter fls state, stay in forwarding or trunkTalking.
};
info.lastSwitchState ← info.switchState;
};
IF feepSpecs#NIL THEN QueueLarkAction[info, feepSpecs];
Must follow switching, but calculations must precede it.
IF keyTable#NIL THEN {
IF ThNet.pd.debug THEN Deb[info, 'K];
keyTablesToDate ← (info.keyTableDistrsRequested ← info.keyTableDistrsRequested+1);
QueueLarkAction[info, keyTable];
};
IF connectionSpec#NIL THEN {
IF ThNet.pd.debug THEN Deb[info, 'C];
SELECT trans FROM
sup, spn, tlk, frd, frn =>
QueueLarkAction[info, connectionSpec];
sgl, sgn =>
IF info.forwardedCall THEN QueueLarkAction[info, connectionSpec];
Otherwise we'd be transmitting stuff for no reason.
ENDCASE;
};
IF larkCall#NIL THEN SELECT tLarkCall[trans] FROM
call => QueueLarkAction[info, larkCall];
ENDCASE;
IF otherAction#NIL THEN {
IF ThNet.pd.debug THEN Deb[info, 'O];
QueueLarkAction[info, otherAction];
};
IF keyTable#NIL THEN WHILE keyTablesToDate > info.keyTablesDistributed DO
WAIT info.keySynch; -- Be sure keys have really been delivered
ENDLOOP;
};
LarkFailed: PUBLIC ERROR [smartsInfo: SmartsInfo] = CODE;
TonesDone: PUBLIC ENTRY PROC[info: LarkInfo, commandEvent: Lark.StatusEvent ] = {
Deb[info, 'z];
SELECT commandEvent.event FROM
'F=> -- Feeping complete
{
IF info.larkState#trunkSignalling THEN RETURN;
EnterLarkSt[info, trunkTalking, NIL];
};
ENDCASE => -- other tones finished.
QueueLarkAction[info, NEW[ATonesDoneType ← [commandEvent.event]]];
};
FlashWait: PUBLIC ENTRY PROC[info: LarkInfo ] = TRUSTED {
ENABLE UNWIND => NULL;
flashWait: CONDITION;
IF info=NIL THEN RETURN;
Process.SetTimeout[@flashWait, Process.MsecToTicks[pd.flashWaitTime]]; -- 600 ms or so.
Deb[info, 'w];
WAIT flashWait;
Deb[info, 'W];
IF info.larkState=trunkTalking THEN -- nothing has gone wrong
<<Alternative: leave it in state fls until now.>>
[]←QueueCommandSequence[info,
larkCommands[info.switchState][info.larkState], @info.lState, info.scratchEv];
};
BlinkLED: PUBLIC ENTRY PROC[info: LarkInfo] = TRUSTED {
ENABLE UNWIND => NULL;
blinkWait: CONDITION;
IF info=NIL THEN RETURN;
WHILE info.forwardedCall AND info.larkState >= trunkSignalling AND info.larkState <= trunkFlashing AND info.larkProcess#NIL DO
Deb[info, 'B];
[]←QueueLarkAction[info, aToggleLED];
Process.SetTimeout[@blinkWait, Process.MsecToTicks[pd.blinkWaitTime]]; -- 500 ms or so.
WAIT blinkWait;
ENDLOOP;
info.blinkProcess ← NIL;
};
QueueFeeps: PUBLIC PROC[sInfo: SmartsInfo, feeps: Rope.ROPE ] = {
EnterLarkState[sInfo.larkInfo, trunkSignalling,
LIST[NEW[Atom.DottedPairNode←[$phoneNumber, feeps]]]];
};
SetupTimeouts: PUBLIC ENTRY PROC[info: LarkInfo, debugging: BOOL ] = {
larkParams: LarkOps.LarkParameters ← NEW[LarkOps.LarkParametersRec[4]];
Server to Lark
RPCTimeouts.SetMaxTransmissions[
conversation: info.shh,
maxTransmissions: pd.toLarkTimeoutTransmissions,
timeoutEnable: SELECT pd.toLarkTimeoutOK FROM
always => always, never => never, unlessDebugging =>
IF debugging THEN never ELSE always, ENDCASE=>dontCare];
Lark to Server
larkParams[0] ← [prDefaultMaxTransmissions, pd.fromLarkTimeoutTransmissions];
larkParams[1] ← [prSignalTimeout, LOOPHOLE[SELECT pd.fromLarkTimeoutOK FROM
always => TRUE, never => FALSE, unlessDebugging => ~debugging, ENDCASE=>ERROR]];
larkParams[2] ← [prEventTimer, pd.larkEventTimer];
larkParams[3] ← [prTimeoutEvents, LOOPHOLE[SELECT pd.larkTimeoutEvents FROM
always => TRUE, never => FALSE, unlessDebugging => ~debugging, ENDCASE=>ERROR]];
larkParams.numParams ← 4;
[]←QueueLarkAction[info, larkParams];
};
Internal Procedures
FailE: ENTRY PROC[info: LarkInfo] = {Fail[info];};
Fail: INTERNAL PROC[info: LarkInfo] = {
IF info.larkState=recovering THEN RETURN;
info.larkState�iled;
info.keyTablesDistributed ← info.keyTableDistrsRequested;
BROADCAST info.keySynch;
};
LarkSupervisor: PROCEDURE[ info: LarkInfo ] = {
In a loop, keep the state of the Lark up to date. Awakens itself whenever any pending
tone is otherwise likely to time out. Awakened by EnterLarkState whenever the state
of tones, switches, and the like might have to change.
ENABLE UNWIND => NULL;
req: REF;
WaitForAction: ENTRY PROC[info: LarkInfo] RETURNS [ref: REFNIL] = TRUSTED {
ENABLE UNWIND=>NULL;
DO
elt: LIST OF REF ← info.newActions;
IF info.larkState=failed OR info.larkState=recovering THEN RETURN[NIL];
IF elt # NIL THEN {
ref𡤎lt.first;
info.newActions ← elt.rest;
RETURN[ref];
};
Process.SetTimeout[@info.stateChange, Process.MsecToTicks[pd.idleWaitTime]];
WAIT info.stateChange;
IF info.newActions = NIL THEN {
IF info.nextToneList#NIL THEN Fail[info]; -- Notification is late.
RETURN[NIL];
};
ENDLOOP;
};
IF info.larkToneSpec=NIL THEN
info.larkToneSpec ← NEW[Lark.ToneSpecRec ← [volume: 0, totalTime: 0, tones: NIL]];
IF info.cSpec=NIL THEN
info.cSpec ← NEW[Lark.ConnectionSpecRec ← [
protocol: interactive,
encoding: muLaw,
sampleRate: 8000,
packetSize: 160,
buffer: in1,
keyIndex: IF ThNet.pd.encryptVoice THEN 1 ELSE 0,
localSocket: [[0],[0], Pup.nullSocket],
remoteSocket: [[0],[0], Pup.nullSocket]
]];
TRUSTED {
Process.EnableAborts[@info.stateChange];
Process.EnableAborts[@info.keySynch];
Process.SetTimeout[@info.stateChange, Process.MsecToTicks[pd.keySynchTime]];
};
When initializing the supervisor process, multicasting should already be off for this host. But be as careful as possible here: stop any that's detectably going on, and in any case, turn off multicast forwarding for this host.
StopMulticast[info];
Multicast.StopHandlingMulticast[shh: info.shh, realHost: info.netAddress.host];
WHILE (req←WaitForAction[info])#NIL DO
-- Deal with communications failure.
ENABLE {
RPC.CallFailed => {
LarkProblem["%g: Call Failed", info]; GOTO Failed; };
ABORTED => {
LarkProblem["%g: LarkSupervisor aborted", info]; GOTO Failed; };
};
DoTones: PROC[newTones: BOOL] = { -- Does one tone from current list of tones
IF info.nextToneList=NIL THEN RETURN;
info.larkToneSpec.volume ← info.toneSpec.volume;
info.expectedNotification ←
IF info.expectedNotification='z THEN 'a ELSE info.expectedNotification+1;
info.larkToneSpec.notification ← [tones, info.expectedNotification];
info.larkToneSpec.tones ← info.nextToneList.first;
[]←info.interface.SpecifyTones[shh: info.shh, queueIt: ~newTones, tones: info.larkToneSpec];
};
WITH req SELECT FROM
d: REF ADisconnectType =>
IF info.spec#NIL THEN {
buf: Lark.VoiceBuffer ← out1;
info.interface.Disconnect[ shh: info.shh, buffer: in1 ]; -- always stop in1 (tx1)
FOR i: NAT IN [1..info.spec.numParties) DO
info.interface.Disconnect[ shh: info.shh, buffer: buf ]; -- out1 (tx1) through outn (txn)
buf ← SUCC[buf];
ENDLOOP;
IF info.multicasting THEN StopMulticast[info];
info.spec ← NIL;
};
spec: ThParty.PartyInfo => {
cSpec: Lark.ConnectionSpec = info.cSpec;
conference: BOOL ← spec.numParties>=3;
IF spec.numParties>=2 THEN {
If conferencing, set up multicasting for this host, first.
info.spec ← spec;
IF conference THEN conference ← StartMulticast[info, spec.conferenceHost];
Transmit buffer
cSpec.buffer ← in1;
cSpec.remoteSocket ← spec[1].socket;
cSpec.remoteSocket.socket ← spec[0].socket.socket;
IF conference THEN cSpec.remoteSocket.host ← spec.conferenceHost.host;
cSpec.localSocket ← cSpec.remoteSocket; -- superstition
info.interface.Connect[shh: info.shh, specs: cSpec ];
Receive buffers
cSpec.buffer ← out1;
FOR i: NAT IN [1..spec.numParties) DO
cSpec.localSocket ← spec[i].socket;
IF conference THEN cSpec.localSocket.host ← spec.conferenceHost.host;
cSpec.remoteSocket ← cSpec.localSocket; -- superstition
info.interface.Connect[shh: info.shh, specs: cSpec ];
cSpec.buffer ← SUCC[cSpec.buffer];
ENDLOOP;
};
};
keyTable: Lark.KeyTable => {
UKT: ENTRY PROC[info: LarkInfo] = INLINE {
info.keyTable ← keyTable;
info.keyTablesDistributed ← info.keyTablesDistributed + 1;
BROADCAST info.keySynch;
};
info.interface.SetKeyTable[shh: info.shh, table: keyTable];
UKT[info];
};
ts: LarkPlay.ToneSpec => {
info.toneSpec←ts;
info.nextToneList ← info.toneSpec.tones;
DoTones[TRUE];
};
lC: ThSmartsPrivate.LarkCall => lC.proc[info, lC.clientData];
See ThsmartsPrivate.LarkCall
td: REF ATonesDoneType => IF info.toneSpec#NIL THEN {
IF td.event#info.expectedNotification THEN GOTO Failed;
IF info.nextToneList#NIL AND info.nextToneList.rest#NIL THEN
info.nextToneList ← info.nextToneList.rest
ELSE IF NOT info.toneSpec.repeatIndefinitely THEN { info.toneSpec←NIL; info.nextToneList←NIL }
ELSE info.nextToneList ← info.toneSpec.tones;
IF info.nextToneList#NIL THEN DoTones[FALSE];
};
a: REF ANoTonesType => {
info.toneSpec←NIL;
info.nextToneList←NIL;
quenchSpec.tones.first.on ← 0;
[]←info.interface.SpecifyTones[shh: info.shh, tones: quenchSpec, queueIt: FALSE];
};
led: REF AToggleLEDType => {
info.lState.lSw[led] ← IF info.lState.lSw[led] = disabled THEN enabled ELSE disabled;
ledToggler[0] ← [led, info.lState.lSw[led]];
[]←info.interface.Commands[info.shh, ledToggler];
};
resetAction: REF ResetActionType => {
[]←info.interface.Reset[shh: info.shh, rName: "Don't revert"];
<<NIL => revert. Remember to change 2d parameter next time Lark.mesa changes.>>
IF info.multicasting THEN StopMulticast[info];
IF info.keyboardResetHandler#NIL THEN info.keyboardResetHandler[info];
};
larkParameters: LarkOps.LarkParameters =>
[]←info.interface.SetParameters[shh: info.shh, parameters: larkParameters];
echoParameters: Lark.EchoParameters =>
[]←info.interface.EchoSupression[shh: info.shh, echo: echoParameters];
commands: Lark.CommandEvents =>
IF commands#NIL THEN info.interface.Commands[ info.shh, commands ];
feepSpecs: REF AFeepType => {
IF feepSpecs=NIL THEN LOOP;
IF (quenchSpec.tones.first.on ← feepSpecs.initialDelay)#0 THEN
[]←info.interface.SpecifyTones[shh: info.shh, tones: quenchSpec, queueIt: FALSE];
[]←info.interface.Feep[
shh: info.shh, on: feepSpecs.on, off: feepSpecs.off, notify: [tones, 'F],
waveTable: ThNet.pd.feepVolume, queueIt: TRUE, events: feepSpecs.digits];
}
ENDCASE;
REPEAT Failed => FailE[info];
ENDLOOP;
info.larkProcess ← NIL;
};
StartMulticast: PROC[info: LarkInfo, hostAddress: Thrush.NetAddress]
RETURNS[ok: BOOLTRUE] = {
IF info.multicasting THEN StopMulticast[info];
IF info.spec=NIL OR info.spec.numParties <=2 THEN RETURN[FALSE];
ok ← Multicast.HandleMulticast[shh: info.shh, net: info.netAddress.net,
realHost: info.netAddress.host, listeningTo: hostAddress.host];
IF ~ok THEN {
VoiceUtils.ProblemFR["Couldn't set multicasting [%g => %g]", $Lark, info,
int[info.netAddress.host], int[hostAddress.host]];
RETURN;
};
info.interface.SetHostNumber[shh: info.shh, host: [hostAddress.net, hostAddress.host]];
info.multicasting ← TRUE;
};
StopMulticast: PROC[info: LarkInfo, force: BOOLFALSE] = {
IF ~info.multicasting THEN RETURN;
info.interface.SetHostNumber[shh: info.shh, host: [info.netAddress.net, info.netAddress.host]];
Multicast.StopHandlingMulticast[shh: info.shh, realHost: info.netAddress.host];
info.multicasting ← FALSE;
};
Queue is a FIFO list of REFs, with a lastAction pointer to aid in rapid enqueuing.
QueueLarkAction: INTERNAL PROC[info: LarkInfo, ref: REF] = {
elt: LIST OF REF = LIST[ref];
lst: LIST OF REF = info.lastAction;
IF info.newActions=NIL THEN info.newActions ← elt ELSE IF lst=NIL THEN ERROR ELSE lst.rest ← elt;
info.lastAction ← elt;
IF info.larkProcess=NIL THEN TRUSTED {
Process.Detach[info.larkProcess ← FORK LarkSupervisor[ info ]]; };
NOTIFY info.stateChange;
};
LarkProblem: PROC[remark: ROPE, info: LarkInfo] = {
VoiceUtils.ProblemFR[remark, $Lark, info, TU.RefAddr[info.larkSmartsInfo]];
};
QueueCommandSequence: INTERNAL PROC[
info: LarkInfo, commands: ROPE,
lState: LONG POINTER TO LState, scratchEv: Lark.CommandEvents]
RETURNS[otherAction: REFNIL]= TRUSTED {
eventIndex: INTEGER←-1;
c: CHAR;
i: NAT;
index: INTEGER;
event: Lark.Event;
events: Lark.CommandEvents ← scratchEv;
nextState: LState ← [];
len: NAT;
IF commands=NIL THEN RETURN; -- status quo
len ← commands.Length[];
See Hardware Switching Tables below for interpretations of these command sequences.
FOR i IN [0..len) DO
SELECT (c𡤌ommands.Fetch[i]) FROM 'J, 'j => IF ~pd.backDoorOH THEN LOOP; ENDCASE;
SELECT c FROM
'Z => { lState^← []; otherAction ← resetAction; }; -- Zap; reset hardware to full idle
'X, 'x => { -- Crossbar switch specification, possibly parameterized by next character
param: CHAR ← commands.Fetch[i+1];
outputs: PACKED ARRAY [0..8) OF BOOLEAN;
row: NAT;
wasParam, doIt: BOOLTRUE;
SELECT param FROM
IN ['0..'9] => wasParam ← FALSE; -- no parameter, just do it.
Parameters determine whether this crossbar specification should be obeyed depending on outside influences, like "line(A/B) mode" or global indications of whether automatically-generated touch-tones should be heard by the caller.
'A => IF info.audioSource#$linea THEN doIt←FALSE;
'B => IF info.audioSource#$lineb THEN doIt←FALSE;
'r => IF info.audioSource=$linea OR info.audioSource=$lineb THEN doIt←FALSE;
't => IF info.transmitOnly THEN doIt←FALSE; -- inhibit all receive switching.
'F => IF ~pd.noisyFeeps THEN doIt←FALSE; -- caller hears auto-feeping
ENDCASE => doIt←FALSE; -- unrecognized parameter, don't do it;
IF wasParam THEN { i←i+1; param ← commands.Fetch[i+1]; };
row ← Digit[param];
outputs ← LOOPHOLE[nextState.xbar[row]];
IF doIt THEN outputs[Digit[commands.Fetch[i+2]]] ← (c='X);
nextState.xbar[row] ← LOOPHOLE[outputs];
i←i+2;
LOOP;
};
'E, 'e => {
nextState.echoStyle ← commands.Fetch[i←i+1]-'0;
otherAction ← echosOn[nextState.echoStyle];
};
'M, 'm => {
nextState.voiceMode ← SELECT commands.Fetch[i←i+1] FROM
'0 => Lark.o3i1,
'1 => Lark.o2i2,
'2 => Lark.o1i1,
ENDCASE => ERROR;
};
ENDCASE=> {
IF c IN ['a..'z] THEN { event ← Lark.disabled; c𡤌-('a-'A); }
ELSE event ← Lark.enabled;
IF lStateForLetter[c]#none THEN nextState.lSw[lStateForLetter[c]] ← event;
};
ENDLOOP;
IF nextState=lState^ THEN RETURN;
IF nextState.echoStyle#lState.echoStyle AND otherAction=NIL THEN
otherAction ← echosOff[lState.echoStyle];
FOR iteration: NAT IN [0..1] DO -- 0: compute size; 1: fill in result sequence.
index←-1;
IF nextState.voiceMode#lState.voiceMode THEN
events[index←index+1] ← [voiceMode, nextState.voiceMode];
FOR i: LSwitches DECREASING IN LSwitches DO IF nextState.lSw[i]#lState.lSw[i] THEN
events[index←index+1] ← [lDevs[i], nextState.lSw[i]]; ENDLOOP;
FOR i: NAT IN [0..8) DO IF nextState.xbar[i]#lState.xbar[i] THEN {
outputs: PACKED ARRAY[0..8) OF BOOLEAN = LOOPHOLE[lState.xbar[i]];
nxtOutputs: PACKED ARRAY[0..8) OF BOOLEAN = LOOPHOLE[nextState.xbar[i]];
FOR j: NAT IN [0..8) DO IF outputs[j]#nxtOutputs[j] THEN
events[index←index+1] ← [
Lark.Device[LOOPHOLE[IF nxtOutputs[j] THEN 23 ELSE 22]],
LOOPHOLE[i*16+j] ];
ENDLOOP;
}; ENDLOOP;
IF index=-1 THEN { events←NIL; EXIT; };
IF iteration=0 THEN events ← NEW[Lark.CommandEventSequence[index+1]]; ENDLOOP;
QueueLarkAction[info, events];
lState^ ← nextState;
lState.lSw[xBarAll] ← Lark.disabled;
};
Digit: PROC[c: CHAR] RETURNS [digit: NAT] = INLINE { RETURN[c-'0]; };
RopeToDTMF: PROC [r: Thrush.ROPE] RETURNS [fs: REF AFeepType] = {
len: INTMIN[Lark.Passel.LAST, r.Length[]];
ce: Lark.CommandEvents;
ceIndex: INT𡤀
number: INTEGER;
fs ← NEW[AFeepType←[]];
FOR rIndex: INT IN [0..len) DO
c: CHAR = r.Fetch[rIndex];
SELECT c FROM
IN ['0..'9], IN ['a..'d], '#, '* => ceIndex ← ceIndex+1;
'P => IF ceIndex#0 THEN ceIndex ← ceIndex+1 ELSE fs.initialDelay ← number*100;
'A => fs.audible ← TRUE;
'O => fs.on ← number*10;
'F => fs.off ← number*10;
IN ['\001..'\037] => number ← c-'\000;
ENDCASE; -- unrecognized, so ignore it.
ENDLOOP;
ce ← NEW[Lark.CommandEventSequence[ceIndex]];
fs.digits ← ce;
ceIndex ← 0;
FOR rIndex: INT IN [0..len) DO
c: CHAR = r.Fetch[rIndex];
val: CHAR ← '\000;
SELECT c FROM
IN ['0..'9] => val ← LOOPHOLE[128 + c - '0];
IN ['a..'d] => val ← LOOPHOLE[138 + c - 'a];
'* => val ← Lark.bStar;
'# => val ← Lark.bThorp;
IN ['\001..'\037] => number ← c-'\000;
'P => IF ceIndex#0 THEN val ← LOOPHOLE[number*10];
ENDCASE;
IF val = '\000 THEN LOOP;
ce[ceIndex] ← [touchPad, val];
ceIndex ← ceIndex+1;
ENDLOOP;
};
SetTones: INTERNAL PROC[] = {
IF ~pd.tonesInvalid THEN RETURN;
pd.tonesInvalid ← FALSE;
dialTone ← NEW[LarkPlay.ToneSpecRec ← [repeatIndefinitely: TRUE,
volume: ThNet.pd.tonesVolume, tones: LIST[LIST[
[f1: 350, f2: 440, on: 5000, off: 0],
[f1: 350, f2: 440, on: 5000, off: 0]]]]];
busyTone ← NEW[LarkPlay.ToneSpecRec ← [repeatIndefinitely: TRUE,
volume: ThNet.pd.tonesVolume, tones: LIST[LIST[
[f1: 480, f2: 620, on: 500, off: 500, repetitions: 5],
[f1: 480, f2: 620, on: 500, off: 500, repetitions: 5]]]]];
errorTone ← NEW[LarkPlay.ToneSpecRec ← [repeatIndefinitely: TRUE,
volume: ThNet.pd.tonesVolume, tones: LIST[LIST[
[f1: 480, f2: 620, on: 250, off: 250, repetitions: 10],
[f1: 480, f2: 620, on: 250, off: 250, repetitions: 10]]]]];
ringbackTone ← NEW[LarkPlay.ToneSpecRec ← [repeatIndefinitely: TRUE,
volume: ThNet.pd.tonesVolume, tones: LIST[LIST[
[f1: 440, f2: 480, on: 2000, off: 4000],
[f1: 440, f2: 480, on: 2000, off: 4000]]]]];
};
Deb: PUBLIC PROC[info: LarkInfo, c: CHAR, p1, p2, p3, p4: IO.Value←[null[]]] = {
s: IO.STREAM;
IF ~ThNet.pd.debug THEN RETURN;
s←IO.ROS[];
s.PutF["<%g", char[c]];
SELECT c FROM
'M => s.PutF["-- %g", p1];
ENDCASE;
s.PutRope[">\r"];
VoiceUtils.Report[s.RopeFromROS[], $LarkDetailed, info];
};
QuickState: ARRAY LarkState OF IO.Value = [
rope["none"], rope["idle"], rope["talking"], rope["trunkSignalling"],
rope["trunkTalking"], rope["trunkForwarding"], rope["trunkFlashing"], rope["failed"], rope["recovering"], rope["ringing"], rope["silence"],
rope["dialTone"], rope["ringBack"], rope["busyTone"], rope["errorTone"]];
Hardware Switching Tables
Interpretation of the command string characters:
En-- echo mode; n IN [0..3); selects echoStyleStd (default), ...FD, ...BD, or ...Fwd
F -- T/R lead reversion
G -- A/A1 hookswitch control reversion
H -- Assert Telewall hookswitch
I -- Assert A/A1 to Telewall
J -- Assert Telewall hookswitch, maybe (depends on boolean variable)
L -- Lights led
l -- Flashes led if trunk is forwarding a call.
R -- overrides volume control for ringing through speaker
S -- enables telset sidetone
T -- spMode; configures codecs for electronic trunk action
Xij -- connects crossbar input i to output j
Xmij -- connects crossbar input i to output j, conditionally
Conditions:
A -- only in lineA mode (input comes from line 1 in instead of telset or microphone)
B -- only in lineB mode (input comes from line 2 in instead of telset or microphone)
r -- only in non-radio (standard, non-lineA/B) mode
t -- inhibit in transmit-only mode (server stuff)
F -- only if feeping (touch-tone signalling) is to be audible.
Mn -- voiceMode; n IN [0..2); selects program O3I1 (default), O2I2, or O1I1
Z -- Resets hardware and crossbar
Radio mode: input comes from line 1 in instead of telset or microphone
Crossbar Connections:
Port Input Output
0 dec1 co1
1 Xmtr Rcvr
2 from Telewall to Telewall
3 mike speaker
4 silence DTMF receiver
5 dec2 co2
6 line 1 in line 1 out
7 line 2 in line 2 out
CommandsForState: TYPE = REF CommandsForStateArray;
CommandsForStateArray: TYPE = ARRAY LarkState OF ROPE;
larkCommands: ARRAY ThSmartsPrivate.SwitchState OF CommandsForState ← [
telsetCommands, -- good as any for "onhook" condition
telsetCommands, -- telset
speakerCommands, -- speaker
speakerCommands, -- sPEAKER
monitorCommands, -- monitor
monitorCommands -- mONITOR
];
telsetCommands: CommandsForState ← NEW[CommandsForStateArray ←
Telset
[ NIL, -- none
"Z", -- idle
"SXt01Xt06Xr10XA60XB70X14", -- talking
"HIX02X06X14XF01", -- trunkSignalling
"HISTX02Xr10XA60XB70Xt21Xt26X14", -- trunkTalking, codec-assisted electronic mode
"E3HIX02X20X24", -- trunkForwarding, trunk to remote Lark connection.
"STX02Xr10XA60XB70Xt21Xt26X14", -- trunkFlashing, on-hook but otherwise trunkTalking.
"Z", -- trunkFlashing, on-hook for a second.
"Z", -- failed
"Z", -- recovering
"RX03X06X14", -- ringing
"SX14", -- silence
toneStdCommand, toneStdCommand, toneStdCommand, toneStdCommand -- tones
]];
toneStdCommand: ROPE = "SX01X14X06";
monitorCommands: CommandsForState ← NEW[CommandsForStateArray ←
Monitoring Telset
[ NIL, -- none
"Z", -- idle
"LSXt01Xt06Xt03Xr10XA60XB70X14", -- talking
"LHIX02X06X03X14XF01", -- trunkSignalling
"LHISTX02Xr10XA60XB70Xt21Xt26Xt23X14", -- trunkTalking, codec-assisted electronic mode
"LE3HIX02X20X24", -- trunkForwarding, trunk to remote Lark connection.
"LSTX02Xr10XA60XB70Xt21Xt26Xt23X14", -- trunkFlashing, on-hook but otherwise trunkTalking.
"Z", -- trunkFlashing, on-hook for a second.
"Z", -- failed
"Z", -- recovering
"RX03X06X14", -- ringing
"LSX14", -- silence
toneMonCommand, toneMonCommand, toneMonCommand, toneMonCommand -- tones
]];
toneMonCommand: ROPE = "LSX01X03X14X06";
speakerCommands: CommandsForState ← NEW[CommandsForStateArray ←
Speakerphone
[ NIL, -- none
"Z", -- idle
"E1LXt03Xt06Xr30XA60XB70X14", -- talking
"LHIX02X06XF03", -- trunkSignalling
"E2M1THILXr30X02Xt25Xt26X24Xt53XA60XB70", -- trunkTalking, gain-controlled digital mode
"LE3HIX02X20X24", -- trunkForwarding, trunk to remote Lark connection. (need gain setting for echo?)
"Z", -- trunkFlashing, on-hook for a second.
"STX02X10X21X26X14", -- trunkFlashing, on-hook but otherwise unchanged.
"Z", -- failed
"Z", -- recovering
"RX03X06", -- ringing
"LX14", -- silence
toneSpkrCommand, toneSpkrCommand, toneSpkrCommand, toneSpkrCommand -- tones
]];
toneSpkrCommand: ROPE = "LX03X14X06";
larkCommands: ARRAY ThSmartsPrivate.SwitchState OF CommandsForState ← [
telsetCommands, -- good as any for "onhook" condition
telsetCommands, -- telset
speakerCommands, -- speaker
speakerCommands, -- sPEAKER
monitorCommands, -- monitor
monitorCommands -- mONITOR
];
echoStyleFD: REFNEW[Lark.EchoParameterRecord ←[
Front Door call using Speakerphone
buffer: out1,
buffer2Controlled: FALSE,
buffer1Controlled: TRUE,
decayTime: 5,
gain: [ 1024, 2048, 2048, 2048, 32767 ]
]];
echoStyleFwd: REF ← echoStyleFD;
echoStyleBD: REFNEW[Lark.EchoParameterRecord ←[
Back Door call using Speakerphone
buffer: in2,
buffer2Controlled: FALSE,
buffer1Controlled: TRUE,
decayTime: 10,
gain: [ 2048, 4096, 8192, 16384, 32767 ]
]];
echoStyleNoFD: REFNEW[Lark.EchoParameterRecord ←[
Standard FD or BD handset mode, no forwarding
buffer: out1, -- not interesting
buffer2Controlled: FALSE,
buffer1Controlled: TRUE, -- FALSE, compensates for a Lark bug; restore when fixed
decayTime: 5,
gain: [ 32767, 32767, 32767, 32767, 32767 ]
]];
echoStyleNoFwd: REF ← echoStyleNoFD;
echoStyleNoBD: REFNEW[Lark.EchoParameterRecord ←[
Standard FD or BD handset mode, no forwarding
buffer: in2, -- not interesting
buffer2Controlled: FALSE,
buffer1Controlled: TRUE, -- FALSE, compensates for a Lark bug; restore when fixed
decayTime: 5,
gain: [ 32767, 32767, 32767, 32767, 32767 ]
]];
echosOn: ARRAY [0..3] OF REF←[ NIL, echoStyleFD, echoStyleBD, echoStyleFwd ];
echosOff: ARRAY [0..3] OF REF←[ NIL, echoStyleNoFD, echoStyleNoBD, echoStyleNoFwd ];
State tables
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
none -- Z --
];
LSTrans: TYPE = {
nop, -- nothing to do
set, -- enter specified state (usu. step to recovery) without taking any other actions.
zap, zpu, zpn, -- reset Lark hardware (u means unconnect first, n means silence tones 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 <<Sep. FD/BD>>)
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 = [[
non idl tlk sig trk fwd fls fai rec rng shh dia rbk bzy err ←new old \/
nop, zap, X, X, X, X, X, X, X, X, X, X, X, X, err ],[-- 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, zpn, X, ksp, trk, frd, X, fai, X, X, nop, X, X, X, X ],[-- sig (trkSignalling)
X, zap, X, sgl, ksp, X, fls, fai, X, X, nop, X, X, X, X ],[-- trk (trkTalking)
X, zpu, X, sgl, 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, zpn, 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, zpn, spn, sgn, tkn, frn, X, fai, X, rng, sil, ksp, rbk, bzy, err ],[-- dia (dialTone)
X, zpn, spn, sgn, tkn, frn, X, fai, X, rng, sil, dia, ksp, bzy, err ],[-- rbk (ringBack)
X, zpn, spn, sgn, tkn, frn, X, fai, X, rng, sil, dia, rbk, ksp, err ],[-- bzy (busyTone)
X, zpn, spn, sgn, tkn, frn, X, fai, X, rng, sil, dia, rbk, bzy, ksp ] -- err (errorTone)
];
Subtransition codes and tables
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, 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; zpn, tkn, spn, sgn, sil
X, X, X, X, stopTones, 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, zpn; trk, tkn, tlk, spn, fls, dia, diu, rbk, rbu, bzy, bzu, err, eru, sil
X, X, reset, 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, zpn, 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, switch, X, switch, X, switch, switch, switch, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switchIfDiff, switch, X, X, X ];
TSetFwd: TYPE = { X, setFwd };
tSetFwd: ARRAY LSTrans OF TSetFwd = [
trk, tkn
X, X, X, X, X, setFwd, setFwd, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X ];
TLarkCall: TYPE = { X, call };
tLarkCall: ARRAY LSTrans OF TLarkCall = [
nop, trk, tkn, frd, frn, tlk, sup, spn, ksp
call, X, X, X, X, call, call, call, call, call, call, call, call, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X ];
Queued specifications for Supervisor
ADisconnectType: TYPE = { aDisconnect };
aDisconnect: REF ADisconnectType ← NEW[ADisconnectType�isconnect];
ResetActionType: TYPE = { resetAction };
resetAction: REF ResetActionType ← NEW[ResetActionType←resetAction];
AFeepType: TYPE = RECORD [
initialDelay: CARDINAL ← pd.waitForTelco,
on: CARDINAL ← pd.telcoMinOn,
off: CARDINAL ← pd.telcoMinOff,
audible: BOOLFALSE,
digits: Lark.CommandEvents←NIL
];
ANoTonesType: TYPE = { aNoTones };
aNoTones: REF ANoTonesType ← NEW[ANoTonesType𡤊NoTones];
ATonesDoneType: TYPE = RECORD [
event: Lark.Event
];
ASpeechDoneType: TYPE = RECORD [
indexMarker: INT
];
AToggleLEDType: TYPE = { aToggleLED };
aToggleLED: REF AToggleLEDType ← NEW[AToggleLEDType𡤊ToggleLED];
ledToggler: Lark.CommandEvents ← NEW[Lark.CommandEventSequence[1]];
ViewCmd: Commander.CommandProc = TRUSTED {
Nice.View[pd, "Lark Out PD"];
};
Commander.Register["VuLarkOut", ViewCmd, "Program Management variables for Lark Output"];
}.
Swinehart, June 14, 1985 5:22:47 pm PDT
Repair Echo stuff
changes to: resetAction (local of LarkSupervisor) explicitly request resets on Z, LarkSupervisor ditto, QueueCommandSequence larkCommands, echosOn, echosOff, ZapEchosType, zapEchos, ANoTonesType, echoStyleNoFD, echoStyleNoBD
Swinehart, July 16, 1985 2:15:11 pm PDT
Fixes to trunkSignalling, trunkForwarding
changes to: EnterLarkSt
Swinehart, August 6, 1985 2:12:11 pm PDT
Merge with PTZ Prose additions
changes to: EnterProseQueue, ASpeechDoneType, ViewCmd
Polle Zellweger (PTZ) July 3, 1985 7:11:31 pm PDT
changes to: DIRECTORY, EnterLarkSt, IntIDQueue, IntIDTranslate, IntIDTranslateBody, EnterIntIDQueue (local of LarkSupervisor), RemoveIntIDQueue (local of LarkSupervisor), LarkSupervisor, HandleProseOutput
Polle Zellweger (PTZ) July 11, 1985 6:20:12 pm PDT
changes to: indexMarkerEnd(public), maxClientMarker(public), LarkSupervisor, ps (local of LarkSupervisor), pd (local of LarkSupervisor), ProseControlDone, EnterProseQueue(replaced EnterIntIDQueue)
removed: RemoveIntIDQueue (function now in LarkInImpl), minClientMarker, minControlMarker, maxControlMarker, speechDoneMarker, DIRECTORY, pResetConfirmOK, cmdLeader, indexMarkerLen, SpeakText (local of LarkSupervisor)
Polle Zellweger (PTZ) July 16, 1985 6:40:42 pm PDT
Fix multiple packets bug.
changes to: LarkSupervisor -- add proseActive & handle incoming speechDoneMarkers correctly=> SpeakText (local of LarkSupervisor), ps (local of LarkSupervisor), pd (local of LarkSupervisor)
Polle Zellweger (PTZ) July 18, 1985 5:18:49 pm PDT
new version of SpeakText preloads Prose and then sends only 1 packet at a time.
changes to: DIRECTORY, LarkOutImpl, LarkSupervisor, SpeakText (local of LarkSupervisor), pd (local of LarkSupervisor), SpeakText, ps (local of LarkSupervisor)
Polle Zellweger (PTZ) July 19, 1985 6:34:34 pm PDT
Make sure not to break in the middle of a client marker!!
changes to: SpeakText (local of LarkSupervisor)
Polle Zellweger (PTZ) July 30, 1985 4:41:39 pm PDT
Lark now has its own copy of newProses; must prune out started and finished reports.
changes to: EnterLarkSt
Polle Zellweger (PTZ) August 19, 1985 5:03:15 pm PDT
Handle Prose flushing.
changes to: maxTextPktLen, maxPkts, numPkts, LarkSupervisor, SpeakText (local of LarkSupervisor), ps (local of LarkSupervisor), pd (local of LarkSupervisor), FilterText, ProseControlDone
Polle Zellweger (PTZ) August 27, 1985 8:58:36 pm PDT
Move local variables from LarkOutImpl.LarkSupervisor into LarkInfo record. These variables are locked by the serial nature of the Lark Supervisor rather than by explicit ENTRY procedures. Reset Prose at Lark startup & idle.
changes to: DIRECTORY, ProseCmd, ProseControlDone, minControlMarker, LarkSupervisor, SpeakText (local of LarkSupervisor), ps (local of LarkSupervisor), pd (local of LarkSupervisor), resetAction (local of LarkSupervisor), FilterText, ProseFlush
Swinehart, October 28, 1985 11:56:38 am PST
Log => VoiceUtils, Handle => ID
changes to: DIRECTORY, LarkOutImpl, ConvDesc, SmartsID, EnterLarkSt, EnterProseQueue, QueueLarkAction
Zellweger (PTZ), November 4, 1985 8:39:52 pm PST
Remove timeout waiting for text-to-speech to report; leave the one for tones in.
changes to: WaitForAction (local of LarkSupervisor)
Swinehart, April 10, 1986 10:05:07 am PST
Revise telset/speakerswitch behavior to integrate $monitor mode, improve things.
changes to: DIRECTORY, SmartsID, PD, EnterLarkSt, FlashWait, QueueCommandSequence, CommandsForState, CommandsForStateArray, larkCommands, telsetCommands, monitorCommands, speakerCommands
Swinehart, May 17, 1986 5:58:28 pm PDT
Cedar 6.1
changes to: LarkSupervisor, StopMulticast
Swinehart, May 25, 1986 10:10:43 pm PDT
Lark => LarkOps
changes to: DIRECTORY, LarkOutImpl
Swinehart, October 21, 1986 5:48:38 pm PDT
Total eradication of remnants of Prose code. Introduction of LarkCall case, to allow things like synthesizers to participate. See LarkSynthesizer(impl)