/* LarkImpl.c 
   Dan Swinehart October 14, 1982  1:25 PM
   L. Stewart October 27, 1982  11:15 PM
   L. Stewart November 9, 1982  9:58 AM, use ctxQ
   L. Stewart December 8, 1982  3:57 PM, silent DTMF events
   L. Stewart December 20, 1982  10:04 AM, more space for EventReport
   L. Stewart December 27, 1982  11:07 PM, ELoad, less space for E.R.
   L. Stewart January 1, 1983  4:11 PM, remove AllocZero
   L. Stewart January 17, 1983  3:47 PM, Lark.mesa revisions
   L. Stewart March 2, 1983, LarkSmarts.mesa bonsai
   L. Stewart March 3, 1983  10:04 AM, Lark.mesa bonsai
   L. Stewart March 6, 1983  3:46 PM, getfixed
   L. Stewart March 10, 1983  11:55 AM, no wf calls
   L. Stewart March 22, 1983  8:57 AM, WDT
   L. Stewart April 18, 1983  10:35 AM, new Lark, LarkSmarts
   LCS May 4, 1983  1:10 PM, New ImportInterface args, retry
   LCS May 24, 1983  4:27 PM, PleaseRegister
   LCS June 13, 1983  4:36 PM, EchoSupression
   LCS July 15, 1983  3:38 PM, SetHostNumber
  */

#include <Queue.h>
#include <Ec.h>
#include <Env.h>
#include <Signal.h>
#include <rpc.h>
#include <rpcinternal.h>
#include <rpclupine.h>
#include <RPCBind.h>
#include <encrypt.h>
#include <LarkNet.h>
#include <RpcBonsai.h>

/* runtime */
extern CallSwat();
extern InitOS();
extern Move2();
extern Swab();
extern Zero();

/* RPC package */
extern int *StartBonsai();
extern CallBonsai();
extern CleanupCall();
extern int diagnoseBinding;
extern int ExportFailed;
extern ExportInterface();
extern int ImportFailed;
extern ImportInterface();
extern struct VersionRange *matchAllVersions;
extern RPCInitialize();
extern RPCInitializeCtx();
extern StartNProcess();
extern int BonsaiDispatcher();
extern struct ShortSTRING *CStringToString();

/* Alloc package */
extern int *GetFixed();

/* Lark package */

/* in LarkEventsImpl.c */
extern InitEventReport();
extern EventReport();
extern EventProcess();
extern AudioStuff();
extern AudioProcess();
extern AudCmd();
extern StartNet();
extern StopNet();

/* context package */
extern Block();
extern CallContext();
extern Dismiss();

/* signaller package */
extern int CONT();

/* pup package */
extern GetPupHost();
extern ELoad();

/* unknown */
extern int mySoc;

/* (Forward) Interface procedures to which Server, below, dispatches */
extern Reset();			/* in LarkAud.c */
extern GenerateTones();		/* in LarkAud.c */
extern Feep();
extern Commands();
extern Connect();
extern Disconnect();
extern PleaseRegister();
extern WhatIsStatus();
extern WhatAreConnections();
extern WhatAreTones();
extern SetKeyTable();
extern CommandString();
extern PleaseLogin();
extern EchoSupression();
extern SetHostNumber();
/* End of interface procedures */

extern struct EncryptionKey nullKeyB;
extern struct Queue ctxQ;

struct Conversation *shhhh;
  /* Place holder for later encrypted conversations */

int smartsHandle[2];
int smartsEpoch[2];
int DEBUG;

struct ImportInstance handle[1];
static struct Seal sl;
static struct InterfaceName larkSmartsInterface;  /* LarkSmarts */

struct ShortSTRING *clientInstance;
struct ShortSTRING *serverInstance;
struct ShortSTRING *clientRname;
static struct ShortSTRING *larkRope;
static struct ShortSTRING *larkSmartsRope;

/* Lark.mesa dispatcher data
 */

static int larkdispspace[20];
struct SSpecsTable *larkSpecs;
int plsRegister;
int plsRegTimer;

Main() {
  CheckWDT();
  InitOS(); /* Sets up sysZone */
  DEBUG = false;
  plsRegister = false;
  shhhh = unencrypted;
  larkRope = CStringToString("Lark.Lark");
  larkSmartsRope = CStringToString("LarkSmarts.Lark");
  CheckWDT();
  RPCInitialize(&ctxQ);
  CheckWDT();
  InitEventReport();
  /* EventProcess is temporary until the interrupt procedures get fixed up */
  StartNProcess("EventProcess", &ctxQ, &EventProcess, 200, 10);
  StartNProcess("EventReport", &ctxQ, &EventReport, 350, 90);
  StartNProcess("AudioProcess", &ctxQ, &AudioProcess, 350, 90);
  CheckWDT();
  InitCtxStats();
  AudioStuff();
  for (;;) {
    CtxListStart();
    PokeWDTA();
    CallContext(ctxQ.head);
    CtxListEnd();
    };
  };

Initialize()
  {
  int serverMachine;
  int bindTries;
  bindTries = 0;
  RPCInitializeCtx(false);
  ELoad();
  diagnoseBinding = true;
  Zero(handle, lenImportInstance);
  Zero(&larkSmartsInterface, lenInterfaceName);
  larkSmartsInterface.type = larkSmartsRope;
  Move2(&larkSmartsInterface.version, matchAllVersions);
  { /* Implicit loop until ENABLE succeeds */
  if (ENABLE(ImportFailed, &CONT, &sl)) {
    bindTries += 1;
    if (bindTries > 10) { CallSwat(ecPup1+100); bindTries = 0; };
    Dismiss(20000);
    };
  while (!AgentInitialize()) {
    bindTries += 1;
    if (bindTries > 10) { CallSwat(ecLarkImpl+23); bindTries = 0; };
    Dismiss(20000);
    };
  /* call Vitae */
  serverMachine = Vitae(GetPupHost(), matchAllVersions, larkSmartsInterface.type, &clientRname, &clientInstance, &serverInstance);
  larkSmartsInterface.instance = serverInstance;
  ImportInterface(serverMachine, &larkSmartsInterface, handle);
  DISABLE(&sl);

  shhhh = StartConversation(clientRname, &nullKeyB, serverInstance, slCBCCheck);
  AttachConversation(handle, shhhh);
  Server(clientInstance);
  Zero(smartsHandle, 2);  /* nil smartsHandle, first time */
  Zero(smartsEpoch, 2);  /* nil smartsEpoch, first time */
  RegisterSelf();

  }; /* endloop */
  };

RegisterSelf() {
  /* bonsai variables */
  struct Seal1 csr;
  int *ap, *sp;
  struct Model *myModel;
  /* new bonsai code for register */
  /* arguments are
	LONG CARDINAL (Lark.SmartsHandle )
	LONG CARDINAL (Epoch (use 0) )
	net,,host	(Lark.Machine)
	Lark.LarkModel:
		genre,,hardwareversion
		software version
	BOOL	(authenticated (use false))
	Rope	(instance from Identify (use clientInstance))

    return values are
	LONG CARDINAL (Lark.SmartsHandle)
   */
  sp = ap = StartBonsai(handle, &csr);
  *ap++ = Swab(iRegister);  /* procedure index */
  *ap++ = smartsHandle[0];  /* zero first time through */
  *ap++ = smartsHandle[1];
  *ap++ = smartsEpoch[0];  /* zero first time through */
  *ap++ = smartsEpoch[1];
  *ap++ = GetPupHost();  /* Lark.Machine */
  myModel = (struct Model *) ap;
  myModel->genre = 1;
  myModel->hardwareVersion = 5;
  myModel->softwareVersion = Swab(6);
  myModel += 1;
  ap = (int *) myModel;
  *ap++ = 0;  /* not authenticated */
  ap = StringToPkt(ap, clientInstance);
  Block();
  CallBonsai(&csr, ap-sp);
  Block();
  ap = sp;
  smartsHandle[0] = *ap++;
  smartsHandle[1] = *ap++;
  smartsEpoch[0] = *ap++;
  smartsEpoch[1] = *ap++;
  CleanupCall(&csr);
  };

static Server(larkInstance)
  struct ShortSTRING *larkInstance;
  {
  struct InterfaceName *larkInterface;
  int *specs;
  /* set up Bonsai dispatcher */
  larkSpecs = (struct SSpecsTable *) larkdispspace;
  Zero(larkdispspace, 20);
  larkSpecs->maxProcs = iSetHostNumber
  larkSpecs->procs[iReset] = (int) &Reset;
  larkSpecs->procs[iGenerateTones] = (int) &GenerateTones;
  larkSpecs->procs[iFeep] = (int) &Feep;
  larkSpecs->procs[iCommands] = (int) &Commands;
  larkSpecs->procs[iConnect] = (int) &Connect;
  larkSpecs->procs[iDisconnect] = (int) &Disconnect;
  larkSpecs->procs[iPleaseRegister] = (int) &PleaseRegister;
  Block();
  larkSpecs->procs[iWhatIsStatus] = (int) &WhatIsStatus;
  larkSpecs->procs[iWhatAreConnections] = (int) &WhatAreConnections;
  larkSpecs->procs[iWhatAreTones] = (int) &WhatAreTones;
  larkSpecs->procs[iSetKeyTable] = (int) &SetKeyTable;
  larkSpecs->procs[iCommandString] = (int) &CommandString;
  larkSpecs->procs[iPleaseLogin] = (int) &PleaseLogin;
  larkSpecs->procs[iEchoSupression] = (int) &EchoSupression;
  larkSpecs->procs[iSetHostNumber] = (int) &SetHostNumber;

  larkInterface = (struct InterfaceName *) GetFixed(lenInterfaceName);
  larkInterface->type = larkRope;
  larkInterface->instance = larkInstance;
  Move2(&larkInterface->version, matchAllVersions);
  Block();
  ExportInterface(larkInterface, &BonsaiDispatcher, larkSpecs);
  };

/* Actual calls via RPC */

struct FeepArgs {
  int procType;
  int on, off, waveTable, queueIt, notify;
  int isNil;
  int lenLo, lenHi;
  struct EvSeq events;
  };

int Feep(sp)
  int *sp;
  {
  int i, thisNotify;
  char d, e, c;
  int tot;
  struct FeepArgs *fa;
  fa = (struct FeepArgs *) sp;
  if (fa->isNil) goto retTrue;
  SwabInPlace(&fa->on, 9);  /* through length field of events */
  thisNotify = 0;
  for (i = 0; i < fa->events.length; i += 1) {
    if ((i + 1) == fa->events.length) thisNotify = fa->notify;
    Block();
    d = fa->events.evs[i].device;
    e = fa->events.evs[i].event;
    if ((e >= 128) && (e <= 137)) c = e - 128 + '0';
    else switch (e) {
      case 138: c = 'A'; break;
      case 139: c = 'B'; break;
      case 140: c = 'C'; break;
      case 141: c = 'D'; break;
      case 142: c = '*'; break;
      case 143: c = '#'; break;
      default: {
        tot = e;
        PlayTone(0, 0, 0, (tot & 0x00ff) * 10, 1, fa->queueIt, fa->waveTable, thisNotify);
        fa->queueIt = true;
        continue;
        };
      };
    LocPlayDTMF(c, fa->on, fa->off, fa->queueIt, fa->waveTable, thisNotify);
    fa->queueIt = true;
    };
  retTrue:
  *sp = swapped1;  /* a Mesa TRUE */
  return(1);
  };

struct CArgs {
  int procType;
  int isNil;
  int lenLo, lenHi;
  struct EvSeq e;
  };

Commands(sp)
  int *sp;
  {
  struct CArgs *ca;
  ca = (struct CArgs *) sp;
  ca->e.length = Swab(ca->e.length);
  if (ca->isNil) return(0);  /* no return values */
  AudCmd(&ca->e);
  return(0);  /* no return values */
  };

struct ConnArgs {
  int procType;
  int isNil;
  struct CSpecs specs;
  };

Connect(sp)
  int *sp;
  {
  struct ConnArgs *ca;
  ca = (struct ConnArgs *) sp;
  if (ca->isNil) return(0);  /* no return values */
  SwabInPlace(&ca->specs, 5);
  StartNet(&ca->specs);
  return (0);  /* no return values */
  };