/* LarkEventsImpl.c
   LCS October 29, 1982  3:16 PM
   LCS December 7, 1982  1:52 PM, tone event
   LCS December 7, 1982  1:52 PM, smaller
   LCS January 14, 1983  4:23 PM, Lark.mesa revisions
   LCS January 17, 1983  3:47 PM, LarkSmarts.mesa bonsai
   LCS March 6, 1983  3:47 PM, remove Alloc
   LCS March 22, 1983  8:58 AM, WDT, more eventcbs
   LCS April 18, 1983  12:04 PM, new LarkSmarts
   LCS May 23, 1983  12:32 PM, PleaseRegister
   LCS June 3, 1983  12:58 PM, success in RecordEvent
   LCS June 12, 1983  2:46 PM, 10 sec timeout in RecordEvent
 */

#include <Queue.h>
#include <Env.h>
#include <Signal.h>
#include <rpc.h>
#include <rpcinternal.h>
#include <rpclupine.h>
#include <RPCBind.h>
#include <Lark.h>
#include <ec.h>
#include <LarkSlave.h>
#include <LarkNet.h>

/* queue package */
extern InitQueue();
extern struct SEventCB *Dequeue();
extern Enqueue();

/* context package */
extern Block();

/* TTY IO package */
extern int AvC();
extern int GetC();

/* runtime package */
extern CallSwat();
extern Swab();

/* analog package */
extern ScanIn();
extern GetPIO();		/* really runtime() */

/* Rest of Lark */
extern int DEBUG;
extern Initialize();

/* RPC package */
extern int *StartBonsai();
extern CallBonsai();
extern CleanupCall();
extern int smartsHandle[1];
extern struct Conversation *shhhh;	/* Place holder for later
			encrypted conversations */
extern struct ImportInstance handle[1];

/* PleaseRegister implementation */
extern int plsRegister;
extern int plsRegTimer;
extern RegisterSelf();

static struct Queue evQ, evFreeQ;
static struct SEventCB evcb[80];
static int *clockPtr;
static int oldAS;
int toneDone;
static int eventInProgress;
static int eventTimer;

InitEventReport()
  {
  int i;
  InitQueue(&evQ);
  InitQueue(&evFreeQ);
  for (i = 0; i < 80; i += 1) Enqueue(&evFreeQ, &evcb[i]);
  clockPtr = clklo;
  };


EventProcess()
  {
  eventInProgress = false;
  for (;;) {
    Block();
    CheckTTY(0);
    CheckTTY(1);
    Block();
    CheckAnalogEvents();
    Block();
    CheckTones();
    PokeWDTB();
    if (eventInProgress && TmrExp(&eventTimer)) {
      CallDebugger(ecLarkImpl + 27);
      plsRegister = false;
      };
    };
  };

static CheckTTY(ch)
  int ch;
  {
  if (AvC(ch)) {
    Enqueue(&evQ, GetSEventCB(4 + ch, GetC(ch)));
    };
  };

static struct SEventCB *GetSEventCB(dev, ev)
  int dev, ev;
  {
  struct SEventCB *p;
  p = Dequeue(&evFreeQ);
  if (p == 0) CallSwat(ecLarkImpl+ 1);
  p->device = dev;
  p->event = ev;
  p->time = Swab(*clockPtr);
  return(p);
  };

static CheckAnalogEvents()
  {
  int i, diff, newAS, ev;
  newAS = ScanIn();
  if (oldAS != newAS) {
    newAS = ScanIn();
    diff = oldAS ↑ newAS;
    if (diff & AIDTMF) {
      if (newAS & AIDTMF) {
        i = (GetPIO(iapioc) >> 4) & 0x0f;
        if ((i > 0) && (i < 10)) ev = i + 128;
        else switch (i) {
          case 0: ev = 141; break;
          case 10: ev = 128; break;
          case 11: ev = 142; break;
          case 12: ev = 143; break;
          case 13: ev = 138; break;
          case 14: ev = 139; break;
          case 15: ev = 140; break;
          default: ev = 145;
          };
        };
      else ev = 145;
      Enqueue(&evQ, GetSEventCB(3 /* DTMF decoder */, ev));
      };
    Block();
    if (diff & AISwitch) {
      Enqueue(&evQ, GetSEventCB(2, (newAS & AISwitch) ? 144: 145));
      };
    if (diff & AIRing) {
      Enqueue(&evQ, GetSEventCB(7, (newAS & AIRing) ? 144: 145));
      };
    if (diff & AIHookSwitch) {
      Enqueue(&evQ, GetSEventCB(1, (newAS & AIHookSwitch) ? 144: 145));
      };
    oldAS = newAS;
    };
  };

static CheckTones()
  {
  if (toneDone != 0) {
    Enqueue(&evQ, GetSEventCB(toneDone >> 8, toneDone & 0377));
    toneDone = 0;
    };
  };

/* This process is the key user of LarkSmarts.Lark" */

EventReport() {
  struct SEvents *e;
  struct SEventCB *p;
  int i;
  /* bonsai variables */
  struct Seal1 csr;
  int *ap;
  int success;

  /* Before entering the loop, do all the initialization stuff
     that must be done with contexts running */

  Initialize();

  for (;;) {
    if (plsRegister && TmrExp(&plsRegTimer)) {
      RegisterSelf();
      plsRegister = false;
      };
    Block();
    p = Dequeue(&evQ);
    if (p == 0) continue;
    /* new bonsai code, variables are above */
    /* someday
    struct Seal sl;
    if (ENABLE(CallFailed, &CONT, &sl)) return (0);
     */
    ap = StartBonsai(handle, &csr);
    e = (struct SEvents *) ap;
    e->procType = Swab(iRecordEvent);  /* procedure index */
    e->smartsLo = smartsHandle[0];  /* Lark.SmartsHandle */
    e->smartsHi = smartsHandle[1];
/* fill it in */
    i = 0;
    for (;;) {
      Block();
      e->eventseq[i].time = p->time;
      e->eventseq[i].device = p->device;
      e->eventseq[i].event = p->event;
      i += 1;
      Enqueue(&evFreeQ, p);
      if (i == 14) break;
      p = Dequeue(&evQ);
      if (p == 0) break;
      };
    Block();
    e->lenLo = e->length = Swab(i);
    e->isNil = e->lenHi = 0;
    SetTmr(10000, &eventTimer);
    eventInProgress = true;
    CallBonsai(&csr, 7 + (i << 1));
    success = *ap;
    CleanupCall(&csr);
    eventInProgress = false;
    /* end of new bonsai code */
    if (success == 0) CallSwat(ecLarkImpl + 26)
    };
  };