/* LoadMeter.c
   Stewart, January 10, 1984  8:48 PM, created
   Stewart, January 11, 1984  11:52 AM, add logic
 */

#include	"LoadMeter.h"

int pSwitch;  /* packets per second switch */
int bSwitch;  /* bits per second switch */
int tSwitch;  /* time constant switch */
int oldpSw;
int oldbSw;
int oldtSw;
int oldSwitch; /* last switch poll value */

/* in memory storage of PIO state */

int pAutob;  /* packets/second autoranging: BOOL */
int bAutob;  /* bits/second autoranging: BOOL */
int bMode;  /* bits/second mode, see LoadMeter.h */
int pMode;  /* packets/second mode, see LoadMeter.h */
int tMode;  /* averaging time mode, see LoadMeter.h */

/* the following three tables describe the connection
   between the various modes and particular LEDs
 */
int pLedCV[4];
int bLedCV[4];
int tLedCV[4];

/* timers */
int tenths;

InitMeter()
  {
  InitLM();
  STimer(500, &tenths);
  };

DoMeter()
  {
  CheckWDT();
  CheckSwitches();
  UpdateLEDs();
  DataCollect();
  };

InitLM()
  {
  InitLMIO();
  InitTables();
  pSwitch = 0;
  bSwitch = 0;
  tSwitch = 0;
  oldpSw = 2;
  oldbSw = 2;
  oldtSw = 2;
  oldSwitch = 0x00A8;
  pAutob = 0;
  bAutob = 0;
  pMode = ModeP30;
  bMode = ModeB3;
  tMode = ModeT03;
  CycleTMode();
  CycleBMode();
  CyclePMode();
  };

InitTables()
  {
  pLedCV[ModeP30] = LedP30;
  pLedCV[ModeP100] = LedP100;
  pLedCV[ModeP300] = LedP300;
  pLedCV[ModeP1000] = LedP1000;
  bLedCV[ModeB3] = LedB3;
  bLedCV[ModeB10] = LedB10;
  bLedCV[ModeB30] = LedB30;
  bLedCV[ModeB100] = LedB100;
  tLedCV[ModeT03] = LedT03;
  tLedCV[ModeT1] = LedT1;
  tLedCV[ModeT3] = LedT3;
  tLedCV[ModeT10] = LedT10;
  };

CheckSwitches()
  {
  int sw;
  sw = InByte(lmpiob);
  SwitchLogic(&oldpSw, sw >> switchPPS, &pSwitch);
  SwitchLogic(&oldbSw, sw >> switchBPS, &bSwitch);
  SwitchLogic(&oldtSw, sw >> switchTC, &tSwitch);
  };

/* pOld is a pointer to an integer holding the "old"
   value of the switch input bits

   new is the new value of the input bits

   pBool is a pointer to a boolean that is set on
   up transitions of the switch

   a down switch shows 1, an up switch shows 2, others
   should be ignored
 */

SwitchLogic(pOld, new, pBool)
  int *pOld, new, *pBool;
  {
  new &= 3;
  if (*pOld == 2 && new == 1) {  /* down transition */
    *pOld = 1;
    return;
    };
  if (*pOld == 1 && new == 2) {  /* up transition */
    *pOld = 2;
    *pBool = true;
    return;
    };
  };

UpdateLEDs()
  {
  if (pSwitch) {
    CyclePMode();
    pSwitch = false;
    };
  if (bSwitch) {
    CycleBMode();
    bSwitch = false;
    };
  if (tSwitch) {
    CycleTMode();
    tSwitch = false;
    };
  };

CycleTMode()
  {
  tMode = ModN(tMode, 4);
  InitData();
  SetLeds(tLedCV, tMode);
  };

CyclePMode()
  {
  CycleFive(&pMode, &pAutob);
  Bit(LedPAuto, pAutob);
  SetLeds(pLedCV, pMode);
  };

CycleBMode()
  {
  CycleFive(&bMode, &bAutob);
  Bit(LedBAuto, bAutob);
  SetLeds(bLedCV, bMode);
  };

/* data handling sections for the Ethernet */

int bps[100];
int pps[100];
int now;
int limit;
int oldPPS;
int oldBPS;

int avgPPS;

/* double precision */
int avgBPS[2];

InitData()
  {
  int i;
  now = 0;
  switch (tMode) {
    case ModeT03: limit = 3; break;
    case ModeT1: limit = 10; break;
    case ModeT3: limit = 30; break;
    case ModeT10: limit = 100; break;
    };
  for (i = 0; i < limit; i += 1) bps[i] = pps[i] = 0;
  };

DataCollect()
  {
  int i;
  if (!Expired(&tenths)) return;
  AddTimer(500, &tenths);
  PollCounters();
  avgPPS = 0;
  avgBPS[0] = avgBPS[1] = 0;
  for (i = 0; i < limit; i += 1) {
    avgPPS += pps[i];
    DoubleIncrement(avgBPS, bps[i]);
    };
  SetMeters();
  };

/* call this every tenth of a second */
PollCounters()
  {
  int newBPS, newPPS;

  newPPS = GetPPS();
  pps[now] = UpdateModFK(oldPPS, newPPS);
  oldPPS = newPPS;

  newBPS = GetBPS();
  bps[now] = UpdateModFK(oldBPS, newBPS);
  oldBPS = newBPS;

  now = ModN(now, limit);
  };

SetMeters()
  {
  int bpsMeter, ppsMeter;
  bpsMeter = 0;
  ppsMeter = 0;
  /* scale the bits per second numbers to 50000 / second */
  /* scale the pps numbers to 1 second *10 and limit them */
  switch (tMode) {
    case ModeT03: {
      /* the number in avgBPS can't be larger than 1500, so
         we can use single prec. arith
       */
      bpsMeter = (avgBPS[0] * 10) / 3; /* ls word */
      ppsMeter = (UMin(avgPPS, MaxP03) * 100) / 3;
      break;
      };
    case ModeT1: {
      bpsMeter = avgBPS[0]; /* ls word */
      ppsMeter = UMin(avgPPS, MaxP1) * 10;
      break;
      };
    case ModeT3: {
      bpsMeter = DoubleUDiv(avgBPS, 3);
      ppsMeter = (UMin(avgPPS, MaxP3) * 10) / 3;
      break;
      };
    case ModeT10: {
      bpsMeter = DoubleUDiv(avgBPS, 10);
      ppsMeter = UMin(avgPPS, MaxP10);
      break;
      };
    };
  /* limit to eventual full scale */
  /* scale bits per second to full scale */
  switch (bMode) {
    case ModeB3: {
      bpsMeter = (UMin(bpsMeter, 1500) / 3) * 100;
      break;
      };
    case ModeB10: {
      bpsMeter = UMin(bpsMeter, 5000) * 10;
      break;
      };
    case ModeB30: {
      bpsMeter = (UMin(bpsMeter, 15000) / 3) * 10;
      break;
      };
    case ModeB100: {
      bpsMeter = UMin(bpsMeter, 50000);
      break;
      };
    };
  /* now map 50000 to 1000 meter FS */
  bpsMeter /= 50;
  /* limit reading to eventual full scale */
  /* scale packets per second to full scale */
  switch (pMode) {
    case ModeP30: {
      ppsMeter = UMin(ppsMeter, 300) * 10 / 3;
      break;
      };
    case ModeP100: {
      ppsMeter = UMin(ppsMeter, 1000);
      break;
      };
    case ModeP300: {
      ppsMeter = UMin(ppsMeter, 3000) / 3;
      break;
      };
    case ModeP1000: {
      ppsMeter = UMin(ppsMeter, 10000) / 10;
      break;
      };
    };
  bpsMeter = Clip(0, bpsMeter, 1000);
  ppsMeter = Clip(0, ppsMeter, 1000);
  SetMeter(1, bpsMeter);
  SetMeter(2, ppsMeter);
  };