/* LarkEventsImpl.c
   L. Stewart October 29, 1982  3:16 PM
   L. Stewart December 7, 1982  1:52 PM, tone event
   L. Stewart December 7, 1982  1:52 PM, smaller
   L. Stewart January 14, 1983  4:23 PM, Lark.mesa revisions
 */

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

/* local definitions */

struct SEvent {
  int time;
  char device;
  char event;
  };

struct SEvents {
  int length;
  struct SEvent eventseq[16];
  };

struct SEventCB {
  struct SEventCB *next;
  int time;
  char device;
  char event;
  };

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

/* context package */
extern Block();

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

/* 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 CallFormatted();
extern struct ShortSTRING *spNl;
extern struct ShortSTRING *spDT;
extern int *smartsHandle;
extern struct Conversation *shhhh;	/* Place holder for later
			encrypted conversations */
extern int handle;

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

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

EventProcess()
  {
  for (;;) {
    Block();
    CheckTTY(0);
    Block();
    CheckTTY(1);
    Block();
    CheckAnalogEvents();
    Block();
    CheckTones();
    };
  };

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 args[5];
  int i;

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

  Initialize();

  for (;;) {
    Block();
    i = 0;
    for (;;) {
      Block();
      p = Dequeue(&evQ);
      if (p) {
        if (DEBUG) wf3("ev time: %04x, dev: %02x, ev %02x\r", p->time, p->device, p->event);
        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;
        };
      else break;
      };
    Block();
    if (i > 0) {
      e.length = i;
      args[0] = (int) smartsHandle;
      args[1] = (int) &e;

      /* need a signal catcher here for callfailed */

      CallFormatted(handle, iRecordEvent, spDT, spNl, args);
      };
    };
  };