/* analog.c
   L. Stewart September 28, 1983, created from Analog
   LCS September 29, 1983  10:18 AM, changed InGain
   LCS September 29, 1983  3:44 PM, added OutGain and initialization
   LCS September 30, 1983  10:26 AM, added SilTabLoc
 */

#include	"Env.h"
#include	"Lark.h"
#include	"LarkSlave.h"
#include	"ec.h"
#include	"LarkNet.h"

/* PIOML.dsm */
extern PIOOn();
extern PIOOff();
extern SetPIO();
extern GetPIO();
extern SetCodec();

/* RegML.dsm */
extern ReadIRR();

/* runtime */
extern StoreW();
extern OutByte();

/* context */

char xBarState[8];

int wdtTimer;
int event;

InitAnalog()
  {
  int row, col;
  /* set up apio Port A, B, C0-3 Out, Port C4-7 In, mode 0 */
  OutByte(apioctl, 0x0088);
  /* initialize state of PIOML statics */
  SetPIO(0x00c0, iapioa);  /* both relays OFF */
  SetPIO(0x0000, iapiob);
  SetPIO(0x000c, iapioc);  /* no ring or sidetone */
  SetPIO(0x00e1, ipioa);  /* LED Off */
  SetPIO(0x0000, ipiob);  /* Host ID really */
  SetPIO(0x0030, ipioc);  /* both relays off */
  SetCodec(0x0c);   /* timeslot 13 */
  ResetAnalogInt();
  /* Everyone silence */
  XbarClear();
  SetIngain(3, 0);
  SetOutgain(0);
  StoreW(SqrSilTab, SilTabLoc);
  };

SetXbar(row, col)
  int row, col;
  {
  int r;
  if (row == 4) {
    for (r = 0; r < 8; r += 1) xbarcom(r, col, false);
    };
  else {
    if (xBarState[col] & 0x10) xbarcom(4, col, false);
    };
  xbarcom(row, col, true);
  };

ClearXbar(row, col)
  int row, col;
  {
  xbarcom(row, col, false);
  if (xBarState[col] == 0) xbarcom(4, col, true);
  };

static xbarcom(row, col, on)
  int row, col, on;
  {
  int data, clock, shift;
  if (on) {
    PIOOn(SwData, iapioc);
    xBarState[col] |= (1 << row);
    };
  else {
    PIOOff(SwData, iapioc);
    xBarState[col] &= ((1 << row) ↑ 0xff);
    };
  data = (col & 3) | ((row & 3) << 2);
  if (row < 4) shift = 0;
  else shift = 1;
  if (col >= 4) shift += 2;
  clock = (SwStb0 << shift);
  SetPIO(data, iapiob);
  SetPIO(clock + data, iapiob);
  SetPIO(data, iapiob);
  };

Revert(active)
  int active;
  {
  if (active) PIOOn(0x0080, iapioa);
  else PIOOff(0x0080, iapioa);
  };

GoOffHook(active)
  int active;
  {
  if (active) PIOOff(0x0040, iapioa);
  else PIOOn(0x0040, iapioa);
  };

ARelay(active)
  int active;
  {
  if (active) PIOOff(0x0010, ipioc);
  else PIOOn(0x0010, ipioc);
  };

RevertHS(active)
  int active;
  {
  if (active) PIOOn(0x0020, ipioc);
  else PIOOff(0x0020, ipioc);
  };

SideTone(active)
  int active;
  {
  if (active) PIOOff(0x0004, iapioc);
  else PIOOn(0x0004, iapioc);
  };

RingEnable(active)
  int active;
  {
  if (active) PIOOff(0x0008, iapioc);
  else PIOOn(0x0008, iapioc);
  };

ResetAnalogInt()
  {
  PIOOff(0x0080, ipioa);
  PIOOn(0x0080, ipioa);
  };

Led(active)
  int active;
  {
  if (active) PIOOff(0x0040, ipioa);
  else PIOOn(0x0040, ipioa);
  };

KickWDT()
  {
  PIOOn(0x0008, ipioa);
  PIOOff(0x0008, ipioa);
  };

PokeWDT()
  {
  KickWDT();
  SetTmr(200, &wdtTimer);
  };

CheckWDT()
  {
  if (TmrExp(&wdtTimer)) PokeWDT();
  };

/* 0 means default, 1 means O3I1, 2 means O2I2 */
StartSlave(prog, length)
  int prog, length;
  {
  int i;
  StoreW(prog, CodeLoc);
  StoreW(length, CodeLen);
  PIOOn(0x20, ipioa);
  for (i=0; i< 20; i+= 1);
  OutByte(dmamode, 0xc0);
  OutByte(dmasmsk, 0x00);
  PIOOff(0x20, ipioa);
  for (i=0; i< 20; i+= 1);
  if (prog != 0) {
    PIOOff(0x10, ipioa);
    PIOOn(0x10, ipioa);
    PIOOff(0x10, ipioa);
    };
  };

SetIngain(ch, gain)
  int ch, gain;
  {
  int v;
  switch (gain) {
    case 0: v = InTab000; break;
    case 1: v = InTab025; break;
    case 2: v = InTab050; break;
    case 3: v = InTab075; break;
    case 4: v = InTab100; break;
    case 5: v = InTab125; break;
    case 6: v = InTab150; break;
    case 7: v = InTab175; break;
    case 8: v = InTab200; break;
    default: v = InTab000;
    };
  if (ch & 1) StoreW(v, In1Gain);
  if (ch & 2) StoreW(v, In2Gain);
  };

SetOutgain()
  {
  StoreW(OutTab00, OutGain);
  };

XbarClear()
  {
  int row, col;
  for (col = 0; col < 8; col += 1) {
    for (row = 0; row < 8; row += 1) xbarcom(row, col, false);
    xbarcom(4, col, true);
    };
  };

NewEvent()
  {
  int newEvent;
  newEvent = 0;
  for (;;) {
    PIOOff(0x000f, iapioa);
    PIOOn(newEvent, iapioa);
    ResetAnalogInt();
    if ((ReadIRR() & 0x0080) == 0) break;
    newEvent += 1;
    if (newEvent == 16) newEvent = 0;
    };
  if (event == newEvent) return(false);
  event = newEvent;
  return(true);
  };

int GetDTMF()
  {
  return(GetPIO(iapioc) >> 4);
  };

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