/* LarkImpl.c 
   Dan Swinehart October 11, 1982 2:16 pm
   L. Stewart October 13, 1982  1:09 PM
   L. Stewart January 1, 1983  4:12 PM, flush AllocZero
   L. Stewart January 3, 1983  1:16 PM, flush CStringToString
 */

#include <Alloc.h>
#include <Queue.h>
#include <Ec.h>
#include <Env.h>
#include <Signal.h>
#include <rpc.h>
#include <rpcinternal.h>
#include <rpclupine.h>
#include <encrypt.h>

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

/* RPC package */
extern AddToDispatcherSpecs();
extern AddType();
extern int CallFormatted();
extern struct ShortSTRING *CStringToString();
extern int diagnoseBinding;
extern int ExportFailed;
extern ExportInterface();
extern int ImportFailed;
extern int ImportInterface();
extern struct VersionRange *matchAllVersions;
extern RPCInitialize();
extern RPCInitializeCtx();
extern int *StartDispatcherSpecs();
extern StartNProcess();
extern int StdDispatcher();

/* Alloc package */
extern int *Allocate();
extern Free();

/* Lark package */

/* in LarkEventsImpl.c */
extern InitEventReport();
extern EventReport();
extern EventProcess();

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

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

/* chario package */
extern wf();
extern wf3();

/* pup package */
extern GetPupHost();

/* unknown */
extern int mySoc;

/* (Forward) Interface procedures to which Server, below, dispatches */
extern Reset();
extern GenerateTones();
extern Feep();
extern Commands();
extern Connect();
extern Disconnect();
extern PleaseRegister();
extern WhatIsStatus();
extern WhatAreConnections();
extern WhatAreTones();
/* End of interface procedures */

extern struct ZN *sysZone;
extern struct EncryptionKey nullKeyB;
static struct Queue ctxQ;

struct ShortSTRING *spNl, *spDT;
static struct ShortSTRING *sp1, *sp2, *sp6;
static struct ShortSTRING *sp8, *spSt, *sp3St, *sp4Sq, *spSt3, *spX;
static struct ShortSTRING *spD1, *spRegister;
static struct ShortSTRING *spSq, *sp1Sq, *sp1X;

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

int *smartsHandle;

/* RPC Procedure indices, Lark interface */
#define iReset			4
#define iGenerateTones		5
#define iFeep			6
#define iCommands		7
#define iConnect 		8
#define iDisconnect 		9
#define iPleaseRegister		10
#define iWhatIsStatus		11
#define iWhatAreConnections	12
#define iWhatAreTones 		13

/* RPC Procedure indices, LarkSmarts interface */
#define iIdentify		4
#define iRegister		5
#define iRecordEvent		6

Main() {
  shhhh = unencrypted;
  InitOS(); /* Sets up sysZone */
  Zero(&ctxQ, 2);
  RPCInitialize(&ctxQ);
  spNl = (struct ShortSTRING *) Allocate(sysZone, 2);
  sp1 = CStringToString("W");
  sp2 = CStringToString("WW");
  sp6 = CStringToString("WWWWWW");
  sp8 = CStringToString("WWWWWWWW");
  spSt = CStringToString("S");
  sp1Sq = CStringToString("WT");
  spSq = CStringToString("K");
  sp3St = CStringToString("WWWS");
  sp4Sq = CStringToString("WWWWK");
  spSt3 = CStringToString("SSS");
  spRegister = CStringToString("DWDSS");
  spX = CStringToString("X"); /* Connection spec */
  sp1X = CStringToString("WX"); /* INTEGER, ConnectionSpec */
  spD1 = CStringToString("D");
  spDT = CStringToString("DT");
  InitEventReport();
  /* EventProcess is temporary until the interrupt procedures get fixed up */
  StartNProcess("EventProcess", &ctxQ, &EventProcess, 200, 10);
  StartNProcess("EventReport", &ctxQ, &EventReport, 350, 90);
  for (;;) {
    CallContext(ctxQ.head);
    };
  };

int handle;
static struct Seal sl;
static struct InterfaceName clientInterface;
static int args[10];  /* prob not needed */

struct Events {
  int length;	/* must be 1 */
  char device;
  char event;
  };

struct Model {
  char hardwareVersion;	/* Swabbed from Mesa version, since */
  char genre;  /*  marshaller will re-Swab */
  int softwareVersion;
  };

#define lenModel (sizeof (struct Model)/2)
  
int pNil[2];
struct ShortSTRING *instance, *serverRname, *myRname;
struct Model *myModel;

Initialize() {
  RPCInitializeCtx(true);
  diagnoseBinding = true;
  AddType('Z', 0);	/* Get things started */
  AddType('X', dBlock(	/* Connection specification */
  	11*16, 		/* eltSize: 11 word elements
			   (VoiceStreams in trailing sequence) */
  	6, 		/* overhead: 5 words + sequence length field */
  	5, 		/* length: Sequence length field */
  	true, 		/* atLen: length is in record at word 5 */
  	true)); 	/* eltWd: all Swabbed, have to reverse some of them */
  AddType('K', dBlock(	/* LarkModel specification */
  	16, 		/* one word elements */
  	1, 		/* sequence only */
  	0,
  	true, 		/* length is in record at word 2 */
  	false)); 	/* deviceStates: sequence of pairs of bytes */
  AddType('T', dBlock(  /* events:  int time; char device, event; */
    32,
    1,
    0,
    true,
    false));
  handle = 0;
  Zero(&clientInterface, lenInterfaceName);
  clientInterface.type = CStringToString("LySmarts.Lark");
  clientInterface.instance = 0;	/* Use broadcast binding methods. */
  Move2(&clientInterface.version, matchAllVersions);
  { /* Implicit loop until ENABLE succeeds */
  if (ENABLE(ImportFailed, &CONT, &sl))
    CallSwat(ecPup1+100);
  handle = ImportInterface(&clientInterface);
  DISABLE(&sl);
  wf("Identify[...] = ");
  args[0] = (int) Swab(GetPupHost());	/* netAddress */
  serverRname = CallFormatted(handle, iIdentify, sp1, spSt3, args);
  myRname = args[2];
  instance = args[3];
  wf3("[serverRname: %r, myRname: %r, instance: %r]\r", serverRname, myRname, instance);
  shhhh = StartConversation(myRname, &nullKeyB, serverRname, slECB);
  wf1("StartConversation[...] = %xH\r", shhhh);
  AttachConversation(&clientInterface, shhhh);
  Server(instance);
  myModel = (struct Model *) Allocate(sysZone, lenModel);
  myModel->genre = 1; /* Lark1 */
  myModel->hardwareVersion = 5; /* or something */
  myModel->softwareVersion = 6; /* or something */
  /* Now register in (once, for now) */
  args[0] = (int) pNil;	/* oldHandle: none yet */
  args[1] = (int) Swab(GetPupHost());	/* netAddress: */
  args[2] = (int) myModel;	/* model: */
  args[3] = (int) instance
  args[4] = (int) myRname; /* <<not sure this still belongs here.>> */
  wf("Register[...] = ");
  smartsHandle = CallFormatted(handle, iRegister, spRegister, spD1, args);
  wf2("%xH, %xH]\r", smartsHandle[0], smartsHandle[1]);
  }; /* endloop */
  };


static Server(instance)
  struct ShortSTRING *instance;
  {
  struct InterfaceName *interface;
  int *specs;
  interface = (struct InterfaceName *) Allocate(sysZone, lenInterfaceName);
  interface->type = CStringToString("Lark.Lark");
  interface->instance = instance;
  Move2(&interface->version, matchAllVersions);
  specs = StartDispatcherSpecs(10);
  AddToDispatcherSpecs(specs, iReset, &Reset, spSt, spNl);
  AddToDispatcherSpecs(specs, iGenerateTones, &GenerateTones, sp8, sp1);
  AddToDispatcherSpecs(specs, iFeep, &Feep, sp4Sq, sp1);
  AddToDispatcherSpecs(specs, iCommands, &Commands, spSq, spNl);
  AddToDispatcherSpecs(specs, iConnect, &Connect, spX, spNl);
  AddToDispatcherSpecs(specs, iDisconnect, &Disconnect, spD1, spNl);
  AddToDispatcherSpecs(specs, iPleaseRegister, &PleaseRegister, spNl, spNl);
  AddToDispatcherSpecs(specs, iWhatIsStatus, &WhatIsStatus, sp1, sp1Sq);
  AddToDispatcherSpecs(specs, iWhatAreConnections, &WhatAreConnections, sp1, sp1X);
  AddToDispatcherSpecs(specs, iWhatAreTones, &WhatAreTones, spNl, sp1);
  ExportInterface(interface, &StdDispatcher, specs);
  };

Reset(rName)
  struct ShortSTRING *rName;
  {
  wf1("Reset[%r]\r", rName);
  Free(sysZone, rName);
  };

GenerateTones(f1, f2, modulation, on, off, repetitions, waveTable, queueIt)
  int f1, f2, modulation, on, off, repetitions, waveTable, queueIt;
  {
  wf4("GenerateTones[f1: %d, f2: %d, mod: %d, on: %d, ",
		f1, f2, modulation, on);
  wf4("off: %d, repetitions: %d, waveTable: %d, queueIt: %s]\r",
		off, repetitions, waveTable, Bool(queueIt));
  };

static char *Bool(x)
  int x;
  {
  return x?"true":"false";
  };

struct Event {
  char device;
  char event;
  };

struct EvSeq {
  int length;
  struct Event evs[2];
  };

int Feep(on, off, waveTable, queueIt, events)
  int on, off, waveTable, queueIt;
  struct EvSeq *events;
  {
  int i; char *evStr;
  wf4("Feep[on: %d, off: %d, waveTable: %d, queueIt: %s, \r	events: ",
  		on, off, waveTable, Bool(queueIt));
  DisplayEvents(events);
  wf(" ]\r");
  Free(sysZone, events);
  return (true);
  };
  
Commands(events)
  struct EvSeq *events;
  {
  wf("Commands[ ");
  DisplayEvents(events);
  wf(" ]\r");
  Free(sysZone, events);
  };

static int evArray[20];

static char *DisplayEvents(events)
  struct EvSeq *events;
  {
  int i, d, e;
  for (i=0; i<events->length; ++i) {
    e=events->evs[i].event;
    d=events->evs[i].device;
    if (e<128) {
      wf2("(%d,%c)", d, e);
      };
    else {
      wf2("(%d,%d)", d, e);
      };
    };
  return (" ");
  };

struct VStream {
  int buffer;
  int key[4];
  int lsoc[3];
  int rsoc[3];
  };

struct CSpecs {
  int id[2];
  int proto;
  int sampleRate;
  int pktSize;
  int length;
  struct VStream stream[8];
  };

Connect(specs)
  struct CSpecs *specs;
  {
  int i;
  wf("Connect[");
  wf2("id0: %04x, id1: %04x,\r", specs->id[0], specs->id[1]);
  wf3("proto: %04x, sampleRate: %d, pktSize: %d,\r", specs->proto, specs->sampleRate, specs->pktSize);
  wf1("nStreams: %d,\r", specs->length);
  for (i = 0; i<specs->length; i += 1) PStream(&specs->stream[i]);
  wf(" ]\r");
  Free(sysZone, specs);
  };

PStream(s)
  struct VStream *s;
  {
  wf1("  buffer: %d,\r", s->buffer);
  wf4("  key: %04x %04x %04x %04x\r", s->key[0], s->key[1], s->key[2], s->key[3]);
  wf3("  lsoc: %04x %04x %04x\r", s->lsoc[0], s->lsoc[1], s->lsoc[2]);
  wf3("  rsoc: %04x %04x %04x\r", s->rsoc[0], s->rsoc[1], s->rsoc[2]);
  };

Disconnect(id)
  int *id;
  {
  wf2("Disconnect[id: [%xH, %xH]]\r", id[0], id[1]);
  Free(sysZone, id);
  };

PleaseRegister()
  {
  wf("PleaseRegister[]\r");
  };

int WhatIsStatus(which)
  int which;
  {
  int res;
  wf1("WhatIsStatus[which: %d] = [0, NIL]\r", which);
  /* args[2] = 0; */ /* FIR can't really handle multiple returns */
  if (which >= 3) res = 0;
  else res = which + 1;
  return (res);
  };

int WhatAreConnections(which)
  int which;
  {
  int res;
  wf1("WhatAreConnections[which: %d] = [0, NIL]\r", which);
  /* args[2] = 0; */ /* FIR can't really handle multiple returns */
  if (which >= 3) res = 0;
  else res = which + 1;
  return (res);
  };

int WhatAreTones()
  {
  wf("WhatAreTones[] = [FALSE]\r");
  return (0);
  };