DIRECTORY AMBridge USING [TVForReferent], BasicTime USING [Now, nullGMT], Buttons USING [ Button, ButtonProc, SetDisplayStyle ], Containers USING [ ChildXBound, Create ], EditedStream USING [DeliverWhenProc, SetEcho], IO, IOUtils USING [CopyPFProcs, PFCodeProc, PFProcs, SetPFCodeProc, SetPFProcs], Lark, LarkRpcControl USING [ImportNewInterface], LarkSmarts, LarkSmartsRpcControl USING [ ExportInterface ], List USING [ Length, Reverse ], Names USING [ CurrentPasskey, CurrentRName, InstanceFromNetAddress ], PlayOps USING [PlayString, BeepProc], PrintTV USING [Print], Process USING [ Detach, MsecToTicks, Pause, SecondsToTicks ], Rope USING [Equal, Fetch, Length, ROPE], RPC USING [AuthenticateFailed, AuthenticateFailure, CallFailed, CallFailure, ImportFailed, ImportFailure, StartConversation, unencrypted], NewLark, TypeScript USING [Create], UserProfile USING [Token], ViewerIO USING [CreateViewerStreams], ViewRec USING [BindAllOfATypeFromRefs, RVQuaViewer, ViewRef], VTables USING [Create, GetTableEntry, Install, SetTableEntry, VTable]; NewLarkImpl: CEDAR PROGRAM IMPORTS AMBridge, BasicTime, Buttons, Containers, EditedStream, IO, IOUtils, LarkRpcControl, LarkSmartsRpcControl, List, Names, NewLark, PlayOps, PrintTV, Process, Rope, RPC, TypeScript, UserProfile, ViewerIO, ViewRec, VTables EXPORTS LarkSmarts = { larkList: LIST OF NewLark.LarkHandle; serialNumber: LarkSmarts.SmartsHandle _ 1; TogProc: Buttons.ButtonProc = TRUSTED { bd: REF NewLark.BDat _ NARROW[clientData]; bd.value _ NOT bd.value; Buttons.SetDisplayStyle[NARROW[parent], IF bd.value THEN $WhiteOnBlack ELSE $BlackOnWhite]; InternalTogProc[bd]; }; InternalTogProc: PROC [bd: REF NewLark.BDat] = { ev: Lark.CommandEvent _ IF bd.value THEN bd.on ELSE bd.off; IF ev.device # nothing THEN SendCommand[self: bd.h, d: ev.device, e: ev.event]; }; ConnProc: Buttons.ButtonProc = TRUSTED { bd: REF NewLark.BDat _ NARROW[clientData]; bd.value _ NOT bd.value; Buttons.SetDisplayStyle[NARROW[parent], IF bd.value THEN $WhiteOnBlack ELSE $BlackOnWhite]; SELECT NARROW[parent, Buttons.Button] FROM VTables.GetTableEntry[table: bd.h.xbv, row: 10, column: 3] => ConnectCommand[self: bd.h, ch: 1, tx: TRUE, on: bd.value]; VTables.GetTableEntry[table: bd.h.xbv, row: 10, column: 4] => ConnectCommand[self: bd.h, ch: 2, tx: TRUE, on: bd.value]; VTables.GetTableEntry[table: bd.h.xbv, row: 10, column: 5] => ConnectCommand[self: bd.h, ch: 3, tx: TRUE, on: bd.value]; VTables.GetTableEntry[table: bd.h.xbv, row: 10, column: 6] => ConnectCommand[self: bd.h, ch: 1, tx: FALSE, on: bd.value]; VTables.GetTableEntry[table: bd.h.xbv, row: 10, column: 7] => ConnectCommand[self: bd.h, ch: 2, tx: FALSE, on: bd.value]; VTables.GetTableEntry[table: bd.h.xbv, row: 10, column: 8] => ConnectCommand[self: bd.h, ch: 3, tx: FALSE, on: bd.value]; ENDCASE => ERROR; }; SetUpXBarViewer: PROC [self: NewLark.LarkHandle] = { sources: ARRAY [0..7] OF Rope.ROPE = ["Codec 1", "TeleSet", "TeleWall", "Mike", "Silence", "Codec 2", "Line 1", "Line 2"]; sinks: ARRAY [0..7] OF Rope.ROPE = ["Codec 1", "TeleSet", "TeleWall", "Speaker", "DTMF", "Codec 2", "Line 1", "Line 2"]; ev: Lark.Event; bd: REF NewLark.BDat; xbv: VTables.VTable; SetUpBDat: PROC [row: NAT, column: NAT, name: Rope.ROPE, bd: REF NewLark.BDat, proc: Buttons.ButtonProc _ TogProc] = { VTables.SetTableEntry[table: xbv, row: row, column: column, name: name, flavor: NIL, proc: proc, clientData: bd, displayStyle: IF bd.value THEN $WhiteOnBlack ELSE $BlackOnWhite, useMaxSize: TRUE]; }; self.xbv _ xbv _ VTables.Create[columns: 9, rows: 11, parent: self.container, y: self.ts.wh]; FOR i: NAT IN [0..7] DO VTables.SetTableEntry[xbv, i + 1, 0, sources[i]]; VTables.SetTableEntry[xbv, 0, i + 1, sinks[i]]; ENDLOOP; FOR row: NAT IN [0..7] DO FOR col: NAT IN [0..7] DO ev _ LOOPHOLE[row*16+col, Lark.Event]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: setCrosspoint, event: ev], off: [device: clearCrosspoint, event: ev], value: FALSE]]; SetUpBDat[row: row + 1, column: col + 1, name: " ", bd: bd]; ENDLOOP; ENDLOOP; bd _ NEW[NewLark.BDat _ [h: self, on: [device: offHookRelay, event: Lark.enabled], off: [device: offHookRelay, event: Lark.disabled], value: FALSE]]; SetUpBDat[row: 9, column: 1, name: "OH", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: aRelay, event: Lark.enabled], off: [device: aRelay, event: Lark.disabled], value: FALSE]]; SetUpBDat[row: 9, column: 2, name: "A", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: revertRelay, event: Lark.enabled], off: [device: revertRelay, event: Lark.disabled], value: FALSE]]; SetUpBDat[row: 9, column: 3, name: "Revert", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: revertHookswitch, event: Lark.enabled], off: [device: revertHookswitch, event: Lark.disabled], value: FALSE]]; SetUpBDat[row: 9, column: 4, name: "HS", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: sideTone, event: Lark.enabled], off: [device: sideTone, event: Lark.disabled], value: FALSE]]; SetUpBDat[row: 9, column: 5, name: "SideTone", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: ringEnable, event: Lark.enabled], off: [device: ringEnable, event: Lark.disabled], value: FALSE]]; SetUpBDat[row: 9, column: 6, name: "RingEnable", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: led, event: Lark.enabled], off: [device: led, event: Lark.disabled], value: FALSE]]; SetUpBDat[row: 9, column: 7, name: "LED", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: spMode, event: Lark.enabled], off: [device: spMode, event: Lark.disabled], value: FALSE]]; SetUpBDat[row: 9, column: 8, name: "SPMode", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: voiceMode, event: Lark.o2i2], off: [device: voiceMode, event: Lark.o3i1], value: FALSE]]; SetUpBDat[row: 10, column: 1, name: "O2I2", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, on: [device: timeslot, event: Lark.ts12], off: [device: timeslot, event: Lark.ts0], value: FALSE]]; SetUpBDat[row: 10, column: 2, name: "TS12", bd: bd]; bd _ NEW[NewLark.BDat _ [h: self, value: FALSE]]; SetUpBDat[row: 10, column: 3, name: "TX1", bd: bd, proc: ConnProc]; bd _ NEW[NewLark.BDat _ [h: self, value: FALSE]]; SetUpBDat[row: 10, column: 4, name: "TX2", bd: bd, proc: ConnProc]; bd _ NEW[NewLark.BDat _ [h: self, value: FALSE]]; SetUpBDat[row: 10, column: 5, name: "VFS-TX", bd: bd, proc: ConnProc]; bd _ NEW[NewLark.BDat _ [h: self, value: FALSE]]; SetUpBDat[row: 10, column: 6, name: "RX1", bd: bd, proc: ConnProc]; bd _ NEW[NewLark.BDat _ [h: self, value: FALSE]]; SetUpBDat[row: 10, column: 7, name: "RX2", bd: bd, proc: ConnProc]; bd _ NEW[NewLark.BDat _ [h: self, value: FALSE]]; SetUpBDat[row: 10, column: 8, name: "RX3", bd: bd, proc: ConnProc]; VTables.Install[xbv]; }; SetUpBDat: PROC [table: VTables.VTable, row: NAT, column: NAT, name: Rope.ROPE, bd: REF NewLark.BDat, proc: Buttons.ButtonProc _ TogProc] = { VTables.SetTableEntry[table: table, row: row, column: column, name: name, flavor: NIL, proc: proc, clientData: bd, displayStyle: IF bd.value THEN $WhiteOnBlack ELSE $BlackOnWhite]; }; MyPlayFile: NewLark.PlayFileProc = TRUSTED { NewLark.PlayFile[fileName: fileName, him: self.rx1.localSocket]; }; MyDialProc: NewLark.DialProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; ce: Lark.CommandEvents _ RopeToDTMF[number]; waveTableNat: NAT _ SELECT waveTable FROM dB0 => 0, dB3 => 1, dB6 => 2, dB9 => 3 ENDCASE => 4; IF self.registered THEN [] _ self.lark.Feep[shh: self.shhh, on: on, off: off, waveTable: waveTableNat, queueIt: queueIt, notify: IF notify THEN [tones, 'F] ELSE [nothing, 0C], events: ce]; }; MyEchoProc: NewLark.EchoProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; echoRec: Lark.EchoParameters _ NEW[Lark.EchoParameterRecord]; echoRec.buffer _ buffer; echoRec.buffer1Controlled _ controlIn1; echoRec.buffer2Controlled _ controlIn2; echoRec.decayTime _ decayTime; echoRec.gain[0] _ g0; echoRec.gain[1] _ g1; echoRec.gain[2] _ g2; echoRec.gain[3] _ g3; echoRec.gain[4] _ g4; IF self.registered THEN self.lark.EchoSupression[shh: self.shhh, echo: echoRec]; }; MySetHostProc: NewLark.SetHostProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; IF self.registered THEN self.lark.SetHostNumber[shh: self.shhh, host: host]; }; MySocketProc: NewLark.SocketProc = { spec: Lark.ConnectionSpec; SELECT buffer FROM in1 => spec _ self.tx1; in2 => spec _ self.tx2; out1 => spec _ self.rx1; out2 => spec _ self.rx2; out3 => spec _ self.rx3; ENDCASE => RETURN; IF buffer = in1 OR buffer = in2 THEN spec.remoteSocket _ socket ELSE spec.localSocket _ socket; }; MyToneProc: NewLark.ToneProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; waveTableNat: NAT _ SELECT waveTable FROM dB0 => 0, dB3 => 1, dB6 => 2, dB9 => 3 ENDCASE => 4; IF self.registered THEN [] _ self.lark.GenerateTones[shh: self.shhh, f1: f1, f2: f2, on: on, off: off, modulation: modulation, repetitions: repetitions, waveTable: waveTableNat, queueIt: queueIt, notify: IF notify THEN [tones, 'T] ELSE [nothing, 0C]]; }; MyTuneProc: NewLark.TuneProc = TRUSTED { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; waveTableNat: NAT _ 0; IF self.registered THEN { ToneOn: PlayOps.BeepProc--PROC[beepFreq: CARDINAL, beepTime: LONG CARDINAL]-- = { [] _ self.lark.GenerateTones[shh: self.shhh, f1: beepFreq, f2: 0, on: beepTime, off: 0, modulation: 0, repetitions: 1, waveTable: waveTableNat, queueIt: TRUE, notify: [nothing, 0C]]; }; PlayOps.PlayString[music: music, file: file, random: FALSE, beepProc: ToneOn]; }; }; MyResetProc: NewLark.BProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; self.msg.PutF["ResetCommand\n"]; IF self.registered THEN self.lark.Reset[self.shhh, self.rName]; }; MyStatusProc: NewLark.BProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; res: CARDINAL _ 0; se: Lark.StatusEvents; self.msg.PutF["StatusStatus => ["]; IF self.registered THEN DO [next: res, events: se] _ self.lark.WhatIsStatus[shh: self.shhh, which: res]; self.msg.PutF["(%d)[%z]", IO.card[res], IO.refAny[se]]; IF res = 0 THEN EXIT; ENDLOOP; self.msg.PutF["]\n"]; }; MyConnStatusProc: NewLark.BProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; res: CARDINAL _ 0; conn: Lark.ConnectionSpec; self.msg.PutF["ConnectStatus => ["]; IF self.registered THEN DO [next: res, specs: conn] _ self.lark.WhatAreConnections[shh: self.shhh, which: res]; self.msg.PutF["(%d)[%z]", IO.card[res], IO.refAny[conn]]; IF res = 0 THEN EXIT; ENDLOOP; self.msg.PutF["]\n"]; }; MyRegisterProc: NewLark.BProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; self.msg.PutF["PleaseRegisterCommand"]; IF self.registered THEN self.lark.PleaseRegister[self.shhh]; self.msg.PutF["\n"]; }; MyToneStatusProc: NewLark.BProc = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; IF self.registered THEN self.msg.PutF["ToneStatus => [%g]\n", IO.refAny[NEW[BOOLEAN _ self.lark.WhatAreTones[shh: self.shhh]]]]; }; MyQuitProc: NewLark.BProc = TRUSTED { self.msg.PutF["Quit\n"]; CleanupProc[self]; }; CleanupProc: NewLark.BProc = { self.pleaseStop _ TRUE; }; MySendAllXBar: NewLark.BProc = { FOR l: LIST OF REF NewLark.BDat _ self.buttons, l.rest UNTIL l = NIL DO InternalTogProc[l.first]; ENDLOOP; }; Identify: PROC [ clientInstance: Rope.ROPE, netAddress: Lark.Machine ] RETURNS [ serverRname: Rope.ROPE, clientRname: Rope.ROPE ] = { h: NewLark.LarkHandle; serverRname _ "Stewart.pa"; clientRname _ Names.InstanceFromNetAddress[netAddress, ".lark"]; h _ FindByName[clientInstance]; IF h = NIL THEN { pf: IOUtils.PFProcs _ IOUtils.CopyPFProcs[NIL]; h _ NEW[NewLark.LarkDataObject]; serialNumber _ serialNumber + 1; h.handle _ serialNumber; larkList _ CONS[h, larkList]; h.container _ Containers.Create[info: [name: h.clientInstance, iconic: FALSE]]; h.ts _ TypeScript.Create[info: [ww: 600, wh: 100, parent: h.container]]; Containers.ChildXBound[container: h.container, child: h.ts]; [in: h.in, out: h.out] _ ViewerIO.CreateViewerStreams[name: "NewLark", viewer: h.ts]; h.msg _ h.out; [] _ IOUtils.SetPFCodeProc[pfProcs: pf, char: 'z, codeProc: MyPrintRef]; [] _ IOUtils.SetPFProcs[stream: h.out, pfProcs: pf]; SetUpXBarViewer[h]; h.cr _ NEW[NewLark.ControlRecord _ [ InGain1: , InGain2: , OutGain: , PlayFile: MyPlayFile, Dial: MyDialProc, Tones: MyToneProc, Tunes: MyTuneProc, Reset: MyResetProc, Status: MyStatusProc, ConnStatus: MyConnStatusProc, Register: MyRegisterProc, ToneStatus: MyToneStatusProc, Quit: MyQuitProc, SendAllXBar: MySendAllXBar, OpenVFS: NewLark.OpenVFS, CloseVFS: NewLark.CloseVFS, Playback: NewLark.Playback, Record: NewLark.Record, Echo: MyEchoProc, SetHost: MySetHostProc, SetSocket: MySocketProc ]]; h.vr _ ViewRec.ViewRef[agg: h.cr, specs: ViewRec.BindAllOfATypeFromRefs[rec: h.cr, handle: NEW[NewLark.LarkHandle _ h]], viewerInit: [wy: h.xbv.wy + h.xbv.wh, ww: h.container.cw, parent: h.container], createOptions: [minRecordWidth: 400]]; h.recordViewer _ ViewRec.RVQuaViewer[h.vr]; h.container.name _ clientInstance; h.tsA _ TypeScript.Create[info: [wy: h.recordViewer.wy + h.recordViewer.wh, ww: 600, wh: 100, parent: h.container]]; Containers.ChildXBound[container: h.container, child: h.tsA]; [in: h.inA, out: h.outA] _ ViewerIO.CreateViewerStreams[name: "Console", viewer: h.tsA, editedStream: FALSE]; EditedStream.SetEcho[self: h.inA, echoTo: NIL]; h.tsB _ TypeScript.Create[info: [wy: h.tsA.wy + h.tsA.wh, ww: 600, wh: 100, parent: h.container]]; Containers.ChildXBound[container: h.container, child: h.tsB]; [in: h.inB, out: h.outB] _ ViewerIO.CreateViewerStreams[name: "Auxiliary", viewer: h.tsB, editedStream: FALSE]; EditedStream.SetEcho[self: h.inB, echoTo: NIL]; h.procA _ FORK LarkTTY[h, TRUE]; -- start console user. TRUSTED { Process.Detach[h.procA]; }; h.procB _ FORK LarkTTY[h, FALSE]; -- start auxiliary user. TRUSTED { Process.Detach[h.procB]; }; }; h.rName _ NIL; h.address _ netAddress; h.serverRname _ serverRname; h.clientRname _ clientRname; h.clientInstance _ clientInstance; h.msg.PutF["Identify[%g, %g, %g]\n", IO.rope[h.serverRname], IO.rope[h.clientRname], IO.rope[h.clientInstance]]; }; FindByName: PROC [instance: Rope.ROPE] RETURNS [h: NewLark.LarkHandle] = { FOR l: LIST OF NewLark.LarkHandle _ larkList, l.rest UNTIL l = NIL DO IF Rope.Equal[instance, l.first.clientInstance, FALSE] THEN RETURN [l.first]; ENDLOOP; RETURN[NIL]; }; FindBySmartsHandle: PROC [smartsHandle: LarkSmarts.SmartsHandle] RETURNS [NewLark.LarkHandle] = { FOR l: LIST OF NewLark.LarkHandle _ larkList, l.rest UNTIL l = NIL DO IF smartsHandle = l.first.handle THEN RETURN [l.first]; ENDLOOP; RETURN [NIL]; }; SetupConnPair: PROC [txBuf, rxBuf: Lark.VoiceBuffer, txAdr, rxAdr: Lark.Machine] RETURNS [tx, rx: Lark.ConnectionSpec] = { tsoca: CARDINAL = 1234; rsoca: CARDINAL = 543; tx _ NEW[Lark.ConnectionSpecRec]; rx _ NEW[Lark.ConnectionSpecRec]; tx.protocol _ rx.protocol _ Lark.Protocol[interactive]; tx.encoding _ rx.encoding _ Lark.Encoding[muLaw]; tx.blankA _ rx.blankA _ 0; tx.sampleRate _ rx.sampleRate _ 8000; tx.packetSize _ rx.packetSize _ 160; tx.blankB _ rx.blankB _ 0; tx.buffer _ txBuf; tx.blankC _ rx.blankC _ 0; tx.keyIndex _ 1; tx.localSocket _ [txAdr.net, txAdr.host, [tsoca, LOOPHOLE[txBuf]]]; tx.remoteSocket _ [rxAdr.net, rxAdr.host, [rsoca, LOOPHOLE[rxBuf]]]; rx.buffer _ rxBuf; rx.keyIndex _ 0; rx.localSocket _ [rxAdr.net, rxAdr.host, [rsoca, LOOPHOLE[rxBuf]]]; rx.remoteSocket _ [txAdr.net, txAdr.host, [tsoca, LOOPHOLE[txBuf]]]; }; RegisterArgs: TYPE = RECORD [ shh: LarkSmarts.SHHH, oldSmartsID: LarkSmarts.SmartsHandle, oldEpoch: LarkSmarts.Epoch, netAddress: Lark.Machine, model: Lark.LarkModel, instance: Rope.ROPE ]; Register: PUBLIC PROC [ shh: LarkSmarts.SHHH_, -- encrypts connection oldSmartsID: LarkSmarts.SmartsHandle _ LarkSmarts.nullHandle, oldEpoch: LarkSmarts.Epoch _ BasicTime.nullGMT, netAddress: Lark.Machine, -- machine name for registering Lark model: Lark.LarkModel_, authenticated: BOOL_FALSE, clientInstance: Rope.ROPE -- obtained from agent ] RETURNS [ smartsID: LarkSmarts.SmartsHandle, epoch: LarkSmarts.Epoch ] = { ra: REF RegisterArgs _ NEW[RegisterArgs _ [ shh: shh, oldSmartsID: oldSmartsID, oldEpoch: oldEpoch, netAddress: netAddress, model: model, instance: clientInstance ]]; h: NewLark.LarkHandle _ FindBySmartsHandle[oldSmartsID]; IF h # NIL THEN { h.msg.PutF["ReRegisterByHandle[instance; %g]\n", IO.rope[clientInstance]]; RETURN [oldSmartsID, oldEpoch]; }; [] _ Identify[clientInstance: clientInstance, netAddress: netAddress]; h _ FindByName[clientInstance]; h.msg.PutF["New Register[instance; %g]\n", IO.rope[clientInstance]]; h.shhh _ RPC.StartConversation[caller: Names.CurrentRName[], callee: h.clientRname, key: Names.CurrentPasskey[], level: CBCCheck ! RPC.AuthenticateFailed => TRUSTED { h.msg.PutF["AuthenticateFailed: %g\r", IO.refAny[NEW[RPC.AuthenticateFailure _ why]]]; h.shhh _ RPC.unencrypted; CONTINUE; }; ]; h.address _ netAddress; [tx: h.tx1, rx: h.rx1] _ SetupConnPair[txBuf: in1, rxBuf: out1, txAdr: netAddress, rxAdr: netAddress]; [tx: h.tx2, rx: h.rx2] _ SetupConnPair[txBuf: in2, rxBuf: out2, txAdr: netAddress, rxAdr: netAddress]; h.rx3 _ SetupConnPair[txBuf: in1, rxBuf: out3, txAdr: netAddress, rxAdr: netAddress].rx; h.model _ model; h.instance _ clientInstance; smartsID _ h.handle; epoch _ BasicTime.Now[]; IF NOT h.registered THEN { h.process _ FORK LarkProc[h]; -- start Diagnostic user. TRUSTED { Process.Detach[h.process]; }; }; }; RecordEvent: PUBLIC PROC [ shh: LarkSmarts.SHHH, smartsID: LarkSmarts.SmartsHandle, whatHappened: Lark.StatusEvents ] RETURNS [success: BOOL]= { h: NewLark.LarkHandle _ FindBySmartsHandle[smartsID]; FOR i: NAT IN [0..whatHappened.length) DO SELECT whatHappened.e[i].device FROM keyboard => h.outA.PutChar[whatHappened.e[i].event ! IO.Error => CONTINUE]; auxiliaryKeyboard => h.outB.PutChar[whatHappened.e[i].event ! IO.Error => CONTINUE]; ENDCASE => InterpretEvent[h, whatHappened.e[i]]; ENDLOOP; RETURN[TRUE]; }; What: SIGNAL = CODE; InterpretEvent: PUBLIC PROC[h: NewLark.LarkHandle, event: Lark.StatusEvent] = {{ ENABLE What => GOTO GiveUp; OnOff: PUBLIC PROC[r: Rope.ROPE, e: Lark.Event] = { h.msg.PutRope[r]; IF e = Lark.enabled THEN h.msg.PutRope[" On\n"] ELSE IF e = Lark.disabled THEN h.msg.PutRope[" Off\n"] ELSE SIGNAL What; }; SELECT event.device FROM speakerSwitch => OnOff["Speaker box Switch", event.event]; ringDetect => OnOff["Ring Detector", event.event]; hookSwitch => OnOff["Telephone Hookswitch", event.event]; tones => OnOff["Tone ", event.event]; touchPad => SELECT event.event FROM IN [Lark.b0..Lark.b9] => h.msg.PutF["DTMF %g\n", IO.char[event.event - '\200 + '0]]; IN [Lark.bA..Lark.bD] => h.msg.PutF["DTMF %g\n", IO.char[event.event - '\212 + 'A]]; Lark.bStar => h.msg.PutRope["DTMF *\n"]; Lark.bThorp => h.msg.PutRope["DTMF #\n"]; Lark.disabled => h.msg.PutRope["DTMF up\n"]; ENDCASE => GOTO GiveUp; ENDCASE => GOTO GiveUp; EXITS GiveUp => h.msg.PutF[" Event(%z)\n", IO.refAny[NEW[Lark.StatusEvent _ event]]]; } }; EventRope: PUBLIC PROC[shh: LarkSmarts.SHHH_, smartsID: LarkSmarts.SmartsHandle_, time: CARDINAL, device: Lark.Device, events: LarkSmarts.ROPE] RETURNS [success: BOOL] = { h: NewLark.LarkHandle _ FindBySmartsHandle[smartsID]; ev: Lark.StatusEvent _ [time, device, '\000]; SELECT device FROM keyboard => h.outA.PutRope[events ! IO.Error => CONTINUE]; auxiliaryKeyboard => h.outB.PutRope[events ! IO.Error => CONTINUE]; ENDCASE => FOR i: INT IN [0..events.Length[]) DO ev.event _ events.Fetch[i]; InterpretEvent[h, ev]; ENDLOOP; RETURN[TRUE]; }; Login: PUBLIC PROC[shh: LarkSmarts.SHHH_, smartsID: LarkSmarts.SmartsHandle_, authenticated: BOOL_TRUE] = { h: NewLark.LarkHandle _ FindBySmartsHandle[smartsID]; h.msg.PutF["Login, authenticated = %g\n", IO.bool[authenticated]]; }; LarkTTY: PROC [self: NewLark.LarkHandle, console: BOOL] = {{ in, out: IO.STREAM; c: CHAR; IF console THEN { in _ self.inA; out _ self.outA; } ELSE { in _ self.inB; out _ self.outB; }; DO ENABLE { IO.Error => TRUSTED { GOTO Cleanup; }; RPC.CallFailed => TRUSTED { out.PutF["\nCallFailed: %g\n", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; c _ in.GetChar[]; IF self.registered THEN { IF console THEN SendCommand[self, Lark.Device[keyboard], c] ELSE SendCommand[self, Lark.Device[auxiliaryKeyboard], c]; }; ENDLOOP; }; EXITS Cleanup => NULL; }; LarkProc: PROC [self: NewLark.LarkHandle] = {{ Process.Pause[Process.SecondsToTicks[1]]; -- let Register results settle. self.lark _ LarkRpcControl.ImportNewInterface[interfaceName: [ type: "Lark.lark", instance: self.instance ] ! RPC.ImportFailed => TRUSTED { self.msg.PutF["ImportFailed: %g\r", IO.refAny[NEW[RPC.ImportFailure _ why]]]; CleanupProc[self]; GOTO Cleanup; }]; self.msg.PutF["Lark ready for business.\n"]; self.registered _ TRUE; DO ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; GOTO Cleanup; }; }; Process.Pause[Process.MsecToTicks[100]]; IF self.cmds # NIL THEN SendCommands[self]; IF self.pleaseStop THEN GOTO Cleanup; ENDLOOP; -- for example. EXITS Cleanup => { self.msg.PutF["Cleanup\n"]; self.registered _ FALSE; self.pleaseStop _ FALSE; }; }; }; SendCommands: PROC [self: NewLark.LarkHandle] = { revcmds: LIST OF REF ANY _ NIL; length: INT _ 0; len: INT _ 0; event: REF Lark.CommandEvent; evs: Lark.CommandEvents _ NIL; revcmds _ self.cmds; self.cmds _ NIL; revcmds _ List.Reverse[revcmds]; DO length _ List.Length[revcmds]; IF length < 1 THEN EXIT; len _ IF length > Lark.Passel.LAST THEN Lark.Passel.LAST ELSE length; evs _ NEW[Lark.CommandEventSequence[len]]; length _ length - evs.length; FOR j: INT IN [0..evs.length) DO event _ NARROW[revcmds.first]; evs.e[j] _ event^; revcmds _ revcmds.rest; ENDLOOP; IF self.registered THEN self.lark.Commands[shh: self.shhh, events: evs]; ENDLOOP; }; SendBool: PROC [self: NewLark.LarkHandle, d: Lark.Device, b: BOOL] = { SendCommand[self, d, IF b THEN Lark.enabled ELSE Lark.disabled]; }; SendCommand: PROC [self: NewLark.LarkHandle, d: Lark.Device, e: Lark.Event] = { event: REF Lark.CommandEvent _ NEW[Lark.CommandEvent _ [device: d, event: e]]; self.cmds _ CONS[event, self.cmds]; }; ConnectCommand: PROC [self: NewLark.LarkHandle, ch: NAT, tx: BOOL, on: BOOL] = { ENABLE { RPC.CallFailed => TRUSTED { self.msg.PutF["CallFailed: %g\r", IO.refAny[NEW[RPC.CallFailure _ why]]]; CleanupProc[self]; CONTINUE; }; }; IF self.registered THEN { onOrOff: Rope.ROPE _ IF on THEN "Connect" ELSE "Disconnect"; txOrRx: Rope.ROPE _ IF tx THEN "transmit" ELSE "receive"; self.msg.PutF["%g %g Channel %d\n", IO.rope[onOrOff], IO.rope[txOrRx], IO.int[ch]]; IF tx AND ch = 3 THEN { IF self.tx3 = NIL THEN { self.msg.PutF["Open VFS first\n"]; RETURN; }; IF on THEN self.lark.Connect[shh: self.shhh, specs: self.tx3] ELSE self.lark.Disconnect[shh: self.shhh, buffer: self.tx3.buffer]; RETURN; }; IF tx AND ch = 2 THEN { IF on THEN self.lark.Connect[shh: self.shhh, specs: self.tx2] ELSE self.lark.Disconnect[shh: self.shhh, buffer: self.tx2.buffer]; RETURN; }; IF tx AND ch = 1 THEN { IF on THEN self.lark.Connect[shh: self.shhh, specs: self.tx1] ELSE self.lark.Disconnect[shh: self.shhh, buffer: self.tx1.buffer]; RETURN; }; IF NOT tx AND ch = 3 THEN { IF on THEN self.lark.Connect[shh: self.shhh, specs: self.rx3] ELSE self.lark.Disconnect[shh: self.shhh, buffer: self.rx3.buffer]; RETURN; }; IF NOT tx AND ch = 2 THEN { IF on THEN self.lark.Connect[shh: self.shhh, specs: self.rx2] ELSE self.lark.Disconnect[shh: self.shhh, buffer: self.rx2.buffer]; RETURN; }; IF NOT tx AND ch = 1 THEN { IF on THEN self.lark.Connect[shh: self.shhh, specs: self.rx1] ELSE self.lark.Disconnect[shh: self.shhh, buffer: self.rx1.buffer]; RETURN; }; }; }; RopeToDTMF: PROC [r: Rope.ROPE] RETURNS [ce: Lark.CommandEvents] = { len: INT _ MIN[Lark.Passel.LAST, r.Length[]]; ce _ NEW[Lark.CommandEventSequence[len]]; FOR j: INT IN [0..ce.length) DO ce.e[j] _ [touchPad, SELECT r.Fetch[j] FROM IN ['0..'9] => LOOPHOLE[128 + r.Fetch[j] - '0], IN ['a..'d] => LOOPHOLE[138 + r.Fetch[j] - 'a], IN ['A..'J] => LOOPHOLE[(r.Fetch[j] - 'A + 1) * 10], '* => Lark.bStar, '# => Lark.bThorp ENDCASE => ' ]; ENDLOOP; }; printDepth: INT _ 8; printWidth: INT _ 64; MyPrintRef: IOUtils.PFCodeProc = TRUSTED { PrintTV.Print[tv: AMBridge.TVForReferent[LOOPHOLE[NARROW[val, IO.Value[refAny]].value]], put: stream, depth: printDepth, width: printWidth]; }; SpOrCR: EditedStream.DeliverWhenProc = TRUSTED { IF char = ' OR char = '\n THEN RETURN [TRUE, TRUE]; RETURN [TRUE, FALSE]; }; LarkSmartsRpcControl.ExportInterface[ interfaceName: [ type: "LarkSmarts.Lark", instance: UserProfile.Token[key: "NewLarkInstance", default: "NULL.Lark"]], user: Names.CurrentRName[], password: Names.CurrentPasskey[] ]; }. May 30, 1984 11:40:55 am PDT, Stewart, Cedar 5, December >NewLarkImpl.mesa Last modified by D. Swinehart, June 19, 1984 12:36:48 pm PDT Last modified by L. Stewart, December 27, 1983 4:58 pm Last Edited by: Pier, May 30, 1984 11:41:13 am PDT This stuff handles the Crossbar viewer (which is a VTable) relays This here's the main loop. compare old and new control records transmit to VFS Edited on May 30, 1984 11:40:18 am PDT, by Pier added UserProfile call to get NewLarkInstance changes to: DIRECTORY, UserProfile, LarkSmartsRpcControl Edited on June 19, 1984 12:35:34 pm PDT, by Swinehart changes to: DIRECTORY, Identify ʽ˜Jšœ™Jšœ<™œ"˜zJšœœ˜Jšœœ˜Jšœœ˜!Jšœœ˜!J˜7J˜1J˜J˜%J˜$J˜J˜J˜J˜Jšœ1œ ˜CJšœ2œ ˜DJ˜J˜Jšœ1œ ˜CJšœ2œ ˜DJ˜J˜—šœœœ˜Jšœœ˜Jšœ%˜%J˜J˜J˜Jšœ˜J˜J˜—šžœœœ˜JšœœŸ˜0Jšœ=˜=J˜/JšœŸ$˜?J˜Jšœœœ˜JšœœŸ˜3JšœœC˜Lšœœœ˜+J˜ Jšœ˜J˜J˜J˜ Jšœ˜J˜—Jšœ8˜8šœœœ˜Jšœ1œ˜JJšœ˜J˜—JšœF˜FJšœ˜Jšœ+œ˜Dšœ œwœœ˜¦Jšœ'œœœ˜VJšœ œ ˜Jšœ˜ J˜—J˜J˜fJ˜fJ˜XJ˜Jšœ˜Jšœ˜J˜šœœœ˜Jšœ œŸ˜7Jšœ ˜'J˜—˜J˜——š ž œœœœGœ œ˜Jšœ5˜5šœœœ˜)šœ˜$Jšœ5œ œ˜KJšœ>œ œ˜TJšœ)˜0—Jšœ˜—Jšœœ˜ J˜—J˜Jšœœœ˜J˜šžœœœ5˜PJšœ œ˜šžœœœ œ˜3Jšœ˜Jšœœ˜/Jšœœœ˜6Jšœœ˜J˜—šœ˜Jšœ:˜:Jšœ2˜2Jšœ9˜9Jšœ%˜%šœ œ ˜#Jšœ/œ!˜TJšœ/œ!˜TJšœ(˜(Jšœ)˜)Jšœ,˜,Jšœœ˜—Jšœœ˜—Jš˜Jšœ%œœ˜OJ˜J˜—J˜šž œœœœ-œ*œœ œ˜«Jšœ5˜5Jšœ-˜-šœ˜Jšœ$œ œ˜:Jšœ-œ œ˜Cš œœœœ˜0Jšœ˜Jšœ˜Jšœ˜——Jšœœ˜ J˜J˜—š žœœœœ6œœ˜kJšœ5˜5Jšœ*œ˜BJ˜—J˜šžœœ%œ˜˜OJšœœœ,˜NJšœ œ˜#J˜J˜—š žœœ œœœ˜Pšœ˜šœœ˜Jšœ"œœœ˜IJ˜Jšœ˜ J˜J˜——šœœ˜Jš œœœœ œ˜