/* Larkaud.c
   LCS   November 1, 1982  9:01 AM,  other stuff
   LCS, November 11, 1982  12:08 PM, CheckFromNet
   LCS, December 7, 1982  1:24 PM, New relays
   LCS, December 8, 1982  4:06 PM, dismiss command, LarkSlave refs
   LCS, January 14, 1983  4:09 PM, Lark.mesa revisions
   LCS, March 2, 1983  3:31 PM, Larkinitial connections
   LCS, March 2, 1983  4:30 PM, bonsai
   LCS, March 6, 1983  3:48 PM, FixedLeft
   LCS, March 10, 1983  9:12 AM, flush wf
   LCS, March 10, 1983  2:12 PM, flush xbar init
   LCS, March 14, 1983  1:27 PM, SPMode
   LCS, March 16, 1983  9:31 AM, AudioProcess moved to LarkNet
   LCS, April 18, 1983  10:32 AM, new Lark
   LCS, April 21, 1983  11:52 AM, correct key parity
   LCS, May 21, 1983  6:40 PM, WhatIsStatus moved to LarkEventsImpl, WhatAreConnections implemented
   LCS, May 24, 1983  4:22 PM, PleaseRegister
   LCS May 27, 1983  4:08 PM, reorganized, echo suppression
   LCS May 31, 1983  7:29 PM, CmdString bugs
   LCS June 2, 1983  11:53 AM, net cleanup
   LCS June 3, 1983  9:51 AM, SetIngain bug, Codec2 wasn't working
   LCS June 5, 1983  5:37 PM, squelchTail, FirstPacket
   LCS June 14, 1983  10:45 AM, EchoSuppression
   LCS July 18, 1983  11:51 AM, SetHostNumber
   LCS August 17, 1983  12:39 PM, parameterize
 */

#include "Lark.h"
#include "Env.h"
#include "RPC.h"
#include "LarkSlave.h"
#include "Queue.h"
#include "Encrypt.h"
#include "Pup.h"
#include "LarkNet.h"
#include "LarkVCB.h"

/* context package */
extern Block();

/* Allocate package */
extern FixedLeft();

/* Lark stuff */
extern InitAnalog();
extern SetIngain();
extern SetOutGain();
extern StartSlave();
extern PlayTone();
extern SetBufferTime();
extern SendPup();
extern Encrypt();
extern ReleasePBI();

extern int localHost;
extern int currentHost;
extern int localNet;
extern int wToneCB;
extern int totAv;
extern int lostTx;
extern struct VCB vcb[1];

extern int keyTable[64];
extern int SSilThresh;
extern int MaxSquelchTail;
extern int ajdelay;
extern int tooLate;
extern int tooEarly;
extern int adjustTooEarly;
extern int firstajdelay;

int bufferClockBad;

int zeroBufferTime;
int bufferPointer;
int bufferClock;

AudioStuff()
  {
  InitAnalog();  /* redundant, it is in InitOS, but restarts... */
  InitNetStuff();
  InitToneStuff();
  SetIngain(3, 0)
  SetOutGain(0)
  SPMode(false);
  StartSlave(1, 0);
  bufferClockBad = 0;
  };

InitNetStuff()
  {
  int i;
  lostTx = 0;
  SSilThresh = 576;
  MaxSquelchTail = 20;
  ajdelay = 10;
  tooLate = 3;
  tooEarly = 40;
  adjustTooEarly = 10;
  firstajdelay = 3;
  for (i = 0; i < 5; i += 1) InitVCB(i);
  SetBufferTime();
  Zero(keyTable, 16 * lenEncryptionKey);
  for (i = 0; i < 16; i += 1) {
    CorrectParity(&keyTable[i]);
    Block();
    };
  };

InitVCB(i)
  int i;
  {
  int j;
  struct VCB *p;
  p = &vcb[i];
  Zero(p, lenVCB);
  switch (i) {
    case IIn1: {
      p->bufbase = InBuf1;
      p->silVal = Sil1Val;
      break;
      };
    case IIn2: {
      p->bufbase = InBuf2;
      p->silVal = Sil2Val;
      break;
      };
    case IOut1: p->bufbase = OutBuf1; break;
    case IOut2: p->bufbase = OutBuf2; break;
    case IOut3: p->bufbase = OutBuf3; break;
    default: return;
    };

  /* variable initialization, others are zero */
  p->firstPacket = true;
  p->silThresh = SSilThresh;
  InitQueue(&p->vpq);
  InitQueue(&p->pq);
  p->pqlength = 0;
  p->squelchTail = MaxSquelchTail;

  /* all but destp and item */
  p->loECB.next = 0;
  p->loECB.srcp = p->bufbase;
  p->loECB.encrypt = true;
  p->loECB.count = 160;
  p->loECB.proc = (int) &SendPup;

  /* hiECB is just like it except for srcp */
  MoveBlock(&p->hiECB, &p->loECB, lenECB);
  p->hiECB.srcp = &p->bufbase[160];

  /* floECB is just like it except . . . */
  MoveBlock(&p->floECB, &p->loECB, lenECB);
  p->floECB.srcp = &p->bufbase[264];
  p->floECB.count = 56;
  p->floECB.proc = (int) &Encrypt;
  p->floECB.item = (int) &p->loECB;

  /* fhiECB is just like it except . . . */
  MoveBlock(&p->fhiECB, &p->loECB, lenECB);
  p->fhiECB.srcp = &p->bufbase[104];
  p->fhiECB.count = 216;

  /* needs srcp, dstp, count, proc, item */
  p->daECB.next = 0;
  p->daECB.encrypt = false;

  /* needs srcp, count, item */
  MoveBlock(&p->dbECB, &p->daECB, lenECB);
  p->dbECB.dstp = p->bufbase;
  p->dbECB.proc = (int) &ReleasePBI;

  /* other echo suppression fields set by the call to Zero */
  p->decayTime = 5;
  for (j = 0; j < 5; j += 1) p->gainTable[j] = 32767;
  };

AudioProcess()
  {
  for (;;) {
    Block();
    PokeWDTC();
    CheckBufferTime();
    TryEcho();
    FromNet();
    };
  };

/* compute the current [zeroBufferTime, bufferPointer] pair */
GetBufferTime()
  {
  int newbp;
  newbp = *BufPtr;

  /* 0 crossing test */
  if (bufferPointer > newbp) zeroBufferTime += 40;
  bufferPointer = newbp;
  bufferClock = zeroBufferTime + (bufferPointer >> 3);
  };

SetBufferTime()
  {
  bufferPointer = *BufPtr;
  zeroBufferTime = ReadTmr() - (bufferPointer >> 3);
  bufferClock = zeroBufferTime + (bufferPointer >> 3);
  };

CheckBufferTime()
  {
  int diff;
  GetBufferTime();
  /* are bufferClock and ct close? */
  diff = bufferClock - ReadTmr();
  if ((diff < -2) || (diff > 2)) {
    SetBufferTime();
    bufferClockBad += 1;
    };
  };

AudCmd(p)
  struct EvSeq *p;
  {
  int i;
  int d, e;
  if (p->length > 20) return;
  for (i = 0; i < p->length; i += 1) {
    Block();
    d = p->evs[i].device;
    e = p->evs[i].event;
    Each(d, e);
    };
  };

static Each(d, e)
  int d, e;
  {
  int on;
  d &= 0x00ff;
  e &= 0x00ff;
  if (e == 144) on = true;
  else on = false;
  switch (d) {
    case 4: PutC(0, e); break;
    case 5: PutC(1, e); break;
    case 8: Revert(on); break;
    case 9: GoOffHook(on); break;
    case 10: SideTone(on); break;
    case 11: RingEnable(on); break;
    case 12: Led(on); break;
    case 13: XbarClear(); break;
    case 14: SetTS(e); break;
    case 15: SetVoice(e); break;
    case 16: case 17:
    case 18: case 19:
      SetTable(d, e); break;
    case 22: YXBar(e); break;
    case 23: XXBar(e); break;
    case 24: RevertHS(on); break;
    case 25: ARelay(on); break;
    case 27: { on = e; Dismiss(on * 10); break; };
    case 28: SPMode(on); break;
    default: break;
    };
  };

static SetTS(c)
  char c;
  {
  if (c == 147) SetCodec(0);
  if (c == 148) SetCodec(0x0c);
  };

static YXBar(c)
  char c;
  {
  ClearXbar(((c >> 4) & 0x0f), (c & 0x0f));
  };

static XXBar(c)
  char c;
  {
  SetXbar(((c >> 4) & 0x0f), (c & 0x0f));
  };

SPMode(on)
  int on;
  {
  int *modep;
  modep = (int *) ModeFlag;
  if (on) *modep |= 3;
  else *modep &= 0xfffc;
  };

static SetVoice(c)
  char c;
  {
  switch (c) {
    case 159: StartSlave(1, 0); break;
    case 160: StartSlave(2, 0); break;
    default: StartSlave(1, 0); break;
    };
  SetBufferTime();
  };

static SetTable(d, e)
  char d, e;
  {
  int table;
  table = e - 149;
  switch (d) {
    case 16: SetIngain(0, table); break;
    case 17: SetIngain(1, table); break;
    case 18: SetOutGain(table); break;
    case 19: SetOutGain(table); break;
    default: break;
    };
  };

/* Actual calls via RPC */

struct ResetArgs {
  int procType;
  int isNil;
  int length;
  /* character array */
  };

/* ropes are stored with only the length word */

int Reset(sp)
  int *sp;
  {
  struct ShortSTRING *rName;
  struct ResetArgs *ra;
  ra = (struct ResetArgs *) sp;
  if (ra->isNil) return(0); /* no results */
  ra->length = Swab(ra->length);
  ra->isNil = ra->length;  /* fake presence of ROPE */
  rName = (struct ShortSTRING *) &ra->isNil;
  AudioStuff(); /* initialize */
  totAv = FixedLeft();
  return (0);  /* no results */
  };

struct GTArgs {
  int procType;
  int f1, f2, modulation, on, off;
  int repetitions, waveTable, queueIt, notify;
  };

int GenerateTones(sp)
  int *sp;
  {
  struct GTArgs *ga;
  int i;
  ga = (struct GTArgs *) sp;
  SwabInPlace(&ga->f1, 9);
  i = PlayTone(ga->f1, ga->f2, ga->on, ga->off, ga->repetitions, ga->queueIt, ga->waveTable, ga->notify);
  *sp = (i) ? swapped1: 0;  /* boolean */
  return (1);  /* one result */
  };

struct DiscArgs {
  int procType;
  int id;
  };

int Disconnect(sp)
  int *sp;
  {
  struct DiscArgs *da;
  da = (struct DiscArgs *) sp;
  StopNet(Swab(da->id));
  return (0);  /* no results */
  };

extern int plsRegister;
extern int plsRegTimer;

int PleaseRegister(sp)
  int *sp;
  {
  SetTmr(2000, &plsRegTimer);
  plsRegister = true;
  return (0);  /* no results */
  };

/*
 struct WACArgs {
    int procType;
    int which;
    };
 */

int WhatAreConnections(sp)
  int *sp;
  {
  int which, i;
  struct VCB *p;
  struct CSpecs *c;
  which = Swab(sp[1]);
  sp += 2;
  c = (struct CSpecs *) sp;
  sp -= 2;
  if ((which >= 0) || (which < 5)) {
   for (i = which; i < 5; i += 1) {
    p = &vcb[i];
    if (p->active) {
      sp[0] = Swab((i == 4) ? 0: i + 1);
      sp[1] = 0;  /* isNil = false */
      c->proto = 0;
      c->sampleRate = Swab(8000);
      c->pktSize = Swab(160);
      c->buffer = Swab(i);
      c->keyIndex = Swab(p->encIndex);
      MoveBlock(&c->lsoc[0], &p->lport, lenPort);
      MoveBlock(&c->rsoc[0], &p->rport, lenPort);
      return (13);
      };
     };
    };
  *sp++ = 0;  /* next = 0 */
  *sp++ = swapped1;  /* isNil = true */
  return (2);  /* two words of results */
  };

int WhatAreTones(sp)
  int *sp
  {
  *sp = (wToneCB) ? swapped1: 0;
  return (1);
  };

/* argument structure
struct KeyArgs {
  int procType;
  int isNil;
  int length[2];
  int sequenceTag;
  int keyArray[64];
  };
 */

int SetKeyTable(sp)
  int *sp
  {
  int i;
  if (sp[1]) return(0);  /* isnil */
  for (i = 0; i < 64; i += 4) {
    CorrectParity(sp + i + 5);
    Block();
    };
  MoveBlock(keyTable, sp+5, 64);
  return (0);
  };

/* argument structure */
struct CmdStrArgs {
  int procType;
  int device;
  int isNil;
  int length;
  char charArray[1];
  };

int CommandString(sp)
  int *sp
  {
  int i;
  struct CmdStrArgs *ca;
  struct ShortSTRING *evString;
  ca = (struct CmdStrArgs *) sp;
  if (ca->isNil) return(0); /* no results */
  ca->length = Swab(ca->length);  /* fix length */
  ca->isNil = ca->length;  /* fake presence of ROPE */
  evString = (struct ShortSTRING *) &ca->isNil;
  for (i = 0; i < evString->length; i += 1) {
    Block();
    Each(Swab(ca->device), evString->text[i]);
    };
  return (0);
  };

int PleaseLogin(sp)
  int *sp;
  {
  *sp = 0;
  return(1);
  };

struct EchoRec {
  int procType;
  int isNil;
  int buffer;
  int control;
  int decayTime;
  int gain[5];
  };

int EchoSupression(sp)
  int *sp;
  {
  struct EchoRec *erp;
  struct VCB *p;
  if (sp[1]) return(0);  /* isnil */
  erp = (struct EchoRec *) sp;
  SwabInPlace(sp + 2, 8);
  erp->buffer &= 07; 
  erp->control &= 03; 
  erp->decayTime &= 037; 
  if (erp->buffer > 4) return(0);
  p = &vcb[erp->buffer];
  p->gainChannel = erp->control;
  p->decayTime = erp->decayTime;
  p->lastEnergy = 0;
  MoveBlock(&p->gainTable[0], &erp->gain[0], 5);
  return(0);
  };

struct SetHostRec {
  int procType;
  char net;
  char host; 
  };

int SetHostNumber(sp)
  int *sp;
  {
  struct SetHostRec *hrp;
  int lh;
  hrp = (struct SetHostRec *) sp;
  lh = hrp->net;
  lh &= 0x00ff;
  if (lh == localNet) {
    lh = hrp->host;
    lh &= 0x00ff;
    if (lh == 0) lh = localHost;
    currentHost = lh;
    NewHost();
    };
  return(0);
  };