LarkTTYImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Last modified by D. Swinehart, August 1, 1987 11:21:10 pm PDT
DIRECTORY
Atom USING [ GetPropFromList, PutPropOnList ],
Commander USING [ CommandProc, Register ],
IO,
RefID USING [ ID, nullID ],
Lark USING [ StatusEvent ],
LarkSmartsMonitorImpl,
Rope USING [ Equal, ROPE ],
RPC USING [ EncryptionKey, ExportFailed ],
LarkOpsRpcControl,
LarkTTY,
LarkTTYRpcControl USING [ ExportInterface ],
ThNet USING [ pd ],
ThParty USING [ RegisterServiceInterface, ReportAction ],
Thrush USING [ ActionID, ActionType, Credentials, InterfaceSpec, NB, noAddress, SHHH, PartyID, SmartsID ],
ThSmartsPrivate USING [ ConvDesc, DBInfo, Deb, EnterLarkState, Fail, GetConv, GetSmartsInfo, LarkCallBody, LarkInfo, RegisterServiceProvider, SmartsInfo ],
VoiceUtils USING [ CmdOrToken, CurrentPasskey, MakeRName, Problem, ProblemFR, ReportFR ]
;
LarkTTYImpl: CEDAR MONITOR LOCKS root
IMPORTS Atom, Commander, IO, root: LarkSmartsMonitorImpl, LarkOpsRpcControl, LarkTTYRpcControl, Rope, RPC, ThNet, ThParty, ThSmartsPrivate, VoiceUtils
EXPORTS LarkTTY
SHARES LarkSmartsMonitorImpl= {
OPEN IO;
Types and Values
LarkInfo: TYPE = ThSmartsPrivate.LarkInfo;
ttyServerSpec: Thrush.InterfaceSpec ← [interfaceName: [type: "LarkTTY"], serviceID: RefID.nullID];
ttyServerUser: Rope.ROPE;
ttyServerPassword: RPC.EncryptionKey;
LarkTTY info, linked to larkInfo. Things will work poorly if there is more than one client at a time for this facility. They won't fail at this level, but the clients will be very unhappy.
LTInfo: TYPE = REF LTInfoBody;
LTInfoBody: TYPE = RECORD [
cDesc: ThSmartsPrivate.ConvDesc ← NIL,
requestingParty: Thrush.PartyID ← TRASH
];
New request from service to Lark:
LarkTTYInit: Commander.CommandProc = {
ttyServerSpec.interfaceName.instance ← NIL;
ttyServerSpec.hostHint ← Thrush.noAddress;
ttyServerUser ← VoiceUtils.MakeRName[style: rName, name:
VoiceUtils.CmdOrToken[cmd: cmd, key: "ThrushServerInstance", default: "Strowger.Lark"]];
ttyServerPassword ← VoiceUtils.CurrentPasskey[VoiceUtils.CmdOrToken[
cmd: cmd, key: "ThrushServerPassword", default: "MFLFLX"]];
ThSmartsPrivate.RegisterServiceProvider[$larktty, LarkTTYRegister];
VoiceUtils.ReportFR["Initialize[LarkTTY.Lark, %s]", $System, NIL, rope[ttyServerUser]];
};
LarkTTYRegister: PROC[
credentials: Thrush.Credentials, smartsInfo: ThSmartsPrivate.SmartsInfo] = {
ENABLE {
RPC.ExportFailed => { VoiceUtils.Problem["LarkTTY export failed", $System]; GOTO CantExportLarkTTY; };
};
exportRequired: BOOL ← ttyServerSpec.interfaceName.instance = NIL;
nb: Thrush.NB;
IF ~ThSmartsPrivate.DBInfo[
partyID: credentials.partyID, attribute: $larktty].value.Equal["true", FALSE] THEN RETURN;
If the database doesn't say you can do it, forget it.
ttyServerSpec.serviceID ← credentials.smartsID; -- identify self.
[nb, ttyServerSpec] ← ThParty.RegisterServiceInterface[credentials: credentials,
interfaceSpecPattern: ttyServerSpec];
IF nb#$success THEN GOTO CantExportLarkTTY;
IF exportRequired THEN LarkTTYRpcControl.ExportInterface[
ttyServerSpec.interfaceName, ttyServerUser, ttyServerPassword!
RPC.ExportFailed => GOTO CantExportLarkTTY];
EXITS
CantExportLarkTTY => {
VoiceUtils.Problem["Couldn't export LarkTTY"]; RETURN; };
};
PutRope: PUBLIC ENTRY PROC
-- TAKES -- [
shhh: Thrush.SHHH,
credentials: Thrush.Credentials, -- authenticates caller
serviceID: RefID.ID, -- identifies particular service
rope: Rope.ROPE
]
RETURNS [nb: Thrush.NB ← $success] = {
ENABLE UNWIND => NULL;
larkInfo: LarkInfo;
cDesc: ThSmartsPrivate.ConvDesc;
smartsInfo: ThSmartsPrivate.SmartsInfo ← ThSmartsPrivate.GetSmartsInfo[serviceID];
ltInfo: LTInfo;
IF smartsInfo=NIL OR smartsInfo.failed THEN RETURN[nb: $noSuchSmarts];
larkInfo ← smartsInfo.larkInfo;
ltInfo ← GetLTInfo[larkInfo];
cDesc ← ThSmartsPrivate.GetConv[smartsInfo, credentials, FALSE];
IF cDesc=NIL THEN RETURN[nb: $noSuchConv];
ltInfo.cDesc ← cDesc;
ltInfo.requestingParty ← credentials.partyID;
Queue the text, counting on standard Lark Failure stuff to recover from problems.
ThSmartsPrivate.EnterLarkState[larkInfo, larkInfo.larkState,
LIST[NEW[ThSmartsPrivate.LarkCallBody ← [IssueCommandString, rope]]]];
};
PutRope.nb~$success
PutRope.nb~$noSuchSmarts
PutRope.nb~$noSuchConv
Lark-to-Server keyboard events
ReportInputEvent: ENTRY PROC [info: LarkInfo, sEvent: Lark.StatusEvent] ~ {
Avoid deadlock - shouldn't call Smarts-level entry procs while holding the LarkIn/Out lock. That's why this isn't an entry procedure.
nb: Thrush.NB;
ltInfo: LTInfo ← GetLTInfo[info];
cDesc: ThSmartsPrivate.ConvDesc ← IF ltInfo=NIL THEN NIL ELSE ltInfo.cDesc;
i: CARDINALLOOPHOLE[sEvent.event];
c: Thrush.ActionID ← i;
IF cDesc=NIL THEN RETURN;
nb ← ThParty.ReportAction[
report: [
self: cDesc.situation.self, -- placeholder
other: cDesc.situation.self,
requestingParty: ltInfo.requestingParty,
actionID: c, -- the actual character, for now (actionInfo later)
actionClass: $larktty,
actionType: $getchar
],
reportToAll: FALSE
].nb;
IF nb = $success THEN RETURN;
IF info#NIL AND ~info.failed THEN ThSmartsPrivate.Fail[info, IO.PutFR["Couldn't report Lark text-input completion -- %g", atom[nb]], TRUE]
ELSE VoiceUtils.ProblemFR["Couldn't report Lark text-input completion, probably due to earlier failure -- %g", $System, NIL, atom[nb]];
};
Utilities
GetLTInfo: INTERNAL PROC[info: LarkInfo] RETURNS [ltInfo: LTInfo←NIL] = {
Synthesizer-specific information is stored on the LarkInfo property list. If that's not true coming in, it's true going out. Also registers the input-handing procedure for keyboard events.
IF info=NIL THEN { VoiceUtils.Problem["No larkInfo at GetLTInfo", $System]; RETURN; };
info.keyboardEventHandler ← ReportInputEvent;
info.keyboardResetHandler ← NIL; -- Probably don't need one.
ltInfo ← NARROW[Atom.GetPropFromList[info.props, $ltInfo]];
IF ltInfo#NIL THEN RETURN;
ltInfo ← NEW[LTInfoBody←[]];
info.props ← Atom.PutPropOnList[info.props, $ltInfo, ltInfo];
};
IssueCommandString: PROC[info: LarkInfo, clientData: REF] = {
textPkt: Rope.ROPE = NARROW[clientData];
IF ThNet.pd.debug THEN ThSmartsPrivate.Deb[info, "Send text to RS232 port", rope[textPkt]];
info.interface.CommandString[shh: info.shh, device: keyboard, commands: textPkt];
};
Commander.Register["LarkTTY", LarkTTYInit, "LarkTTY <ExportInstance[Strowger]> <ServerPassword[...]>\nInitialize and Export Lark TTY (char aux input/output) Implementation."];
}.
Swinehart, May 8, 1987 9:03:47 am PDT
Derived from LarkSynthesizer code. Allows Lark to be used, relatively independently of telephone service, to read and write characters from an RS-232 port., ttyServerSpec, ttyServerUser, ttyServerPassword, }, LarkTTYRegister, SynthReport, PutRope, ReportInputEvent, GetSynthInfo, IssueCommandString, LTInfo, LTInfoBody