/* echouser.c
   L. Stewart November 28, 1982  6:48 PM
   D. Swinehart July 9, 1982  2:15 PM
   L. Stewart February 11, 1983  9:55 AM, add routing table print
   L. Stewart April 29, 1983  8:22 PM, WDT
   L. Stewart July 7, 1983  11:13 AM, routing
   L. Stewart July 15, 1983  3:59 PM, change host command
 */

#include <Ec.h>
#include <Env.h>
#include <Queue.h>
#include <Pup.h>
#include <Lark.h>
#include <LarkNet.h>


extern struct Queue ctxQ;
static struct Port echoPort;
static struct Port lclPort;
static int echob;
static int audb;
static int dnet, dhost;
static int speedy;
static int speedytmr;
static int echoPkts;
static int loopCtx;
static int loopSpace;
static int prCtx;
static int prSpace;
static int cpCtx;
static int cpSpace;
static int rcvflag;
static int counter;
static int leftover, any;
extern struct Route routingTable[maxNetworks];

extern /*forward*/Loop();
extern /*forward*/InE();
extern /*forward*/In();
extern /*forward*/cp();
extern /*forward*/pr();

extern int currentHost;

main()
  {
  InitOS();
  InitPupLevel1(&ctxQ, 10, defaultPupDataBytes);
  loopSpace = GetFixed(300);
  loopCtx = InitNContext("Loop", loopSpace, 300, &Loop);
  Enqueue(&ctxQ, loopCtx);
  cpSpace = GetFixed(1000);
  cpCtx = InitNContext("command", cpSpace, 1000, &cp);
  Enqueue(&ctxQ, cpCtx);
  prSpace = GetFixed(1000);
  prCtx = InitNContext("print", prSpace, 1000, &pr);
  Enqueue(&ctxQ, prCtx);
  echob = 0;
  speedy = 0;
  counter = 0;
  dnet = 0x007b;
  dhost = 0x004a;
  echoPort.socket.LS = 0;
  echoPort.socket.ms = Swab(5);
  echoPort.host = 0;
  echoPort.net = 0;
  lclPort.socket.LS = 123;
  lclPort.socket.ms = 456;
  lclPort.host = 0;
  lclPort.net = 0;
  if (!OpenLevel1Socket(&echoPort, &InE, 0)) CallSwat(ecPup1+10);
  if (!OpenLevel1Socket(&lclPort, &In, 0)) CallSwat(ecPup1+10);
  ELoad();
  for (;;) {
    CtxListStart();
    CallContext(ctxQ.head);
    CtxListEnd();
    CheckWDT();
    };
  };

static cp()
  {
  char c;
  wf("Pup Echo user and server.\r");
  for(;;) {
      wf("@ ");
      while (!Chav()) Block();
      c = GetChar();
      switch (c) {
        case 'a': audb = 1; doaud(); break;
        case 'b': audb = 0; doaud(); break;
        case 'c': SetHost(); break;
        case 'e': echob = 1; break;
        case 'f': echob = 0; break;
        case 'h': host(); break;
        case 'n': net(); break;
	case 's':
	  speedy = 1; counter = 0; SetTmr(1000, &speedytmr); break;
	case 'r': PrintRT(); break;
	case 't': speedy = 0; break;
        default: help(); break;
        };
      };
  };

doaud()
  {
  if (audb) StartSlave(1, 0);
  else PIOOn(0x0020, ipioa);
  };

PrintRT()
  {
  int i;
  for (i = 0; i < 256; i += 1) {
    Block();
    if (Chav()) break;
    wf4("net %3d, host %3o, hops %d, age %d\r", i, routingTable[i].host & 0x00ff, routingTable[i].hops & 0x00ff, routingTable[i].age & 0x00ff);
    };
  };

static AddToTimer(t, i)
  int *t, i;
  {
  *t += i;
  };

static pr()
  {
  for(;;) {
    Block();
   if (speedy && TmrExp(&speedytmr)) {
      AddToTimer(&speedytmr, 1000);
      wf2("Pkts/sec: User = %6d, Server = %6d\r", counter, echoPkts);
      echoPkts = counter = 0;
      };
    };
  };

static help()
  {
  wf("a: audio on, b: off\r");
  wf("e: echo on, f: off\r");
  wf("s: fast on, t: off\r");
  wf("h: host, n: net\r");
  wf("p: print stuff\r");
  };

static net()
  {
  wf(" net: ");
  dnet = gethex();
  wf1(" (= %x)\r", dnet);
  };

static host()
  {
  wf(" host: ");
  dhost = gethex();
  wf1(" (= %x)\r", dhost);
  };

static SetHost()
  {
  int nhost;
  wf(" change host to: ");
  nhost = gethex();
  wf1(" (= %x)\r", nhost);
  currentHost = nhost;
  NewHost();
  };

static Loop()
  {
  int echotmr;
  struct Pup *p;
  struct PBI *tPBI;
  char foo[8];
  foo[0] = 4;
  foo[1] = 0;
  foo[2] = 4;
  foo[3] = 0;
  foo[4] = 'A';
  foo[5] = 'b';
  foo[6] = 'c';
  foo[7] = 'd';
  for (;;) {
    Block();
    if (echob) {
      rcvflag = 0;
      tPBI = GetPBI(5);
      p = tPBI->pup;
      Zero(p, 10);
      p->type = 1;
      p->id[0] = Swab(++counter);
      p->dPort.net = dnet;
      p->dPort.host = dhost;
      p->dPort.socket.LS = 0;
      p->dPort.socket.ms = Swab(5);
      p->sPort.net = 0173;
      p->sPort.host = EtherHost();
      p->sPort.socket.LS = lclPort.socket.LS;
      p->sPort.socket.ms = lclPort.socket.ms;
      AppendStringToPup(tPBI, 4, foo);
      SendPup(tPBI);
      SetTmr(1000, &echotmr);
      while (!TmrExp(&echotmr) && (!rcvflag)) {
        Block();
        };
      if (!rcvflag) PutChar('?');
      else { if (!speedy) PutChar('!'); }; 
      };
    };
  };

static int gethex()
  {
  int v;
  v = 0;
  any = 0;
  for (;;) {
    eGetChar();
    if (IsDigit(leftover)) {
      v = (v<<4);
      v += (leftover-'0');
      any = 1;
      continue;
      };
    leftover = LC(leftover);
    if (leftover>='a' && leftover<='f') {
      v = (v<<4);
      v += (leftover-'a'+10);
      any = 1;
      continue;
      };
    break;
    };
  return(v);
  };

static int eGetChar()  /* GetChar with echo */
  {
  while (!Chav()) Block();
  leftover = GetChar() & 0177;
  PutCRChar(leftover);
  return(leftover);
  };

static In(pbi)
  struct PBI *pbi;
  {
  if (!CheckCheckSum(pbi->pup)) PutChar('c');
  rcvflag = 1;
  ReleasePBI(pbi);
  };

static InE(pbi)
  struct PBI *pbi;
  {
  if (!CheckCheckSum(pbi->pup)) PutChar('c');
  if (pbi->pup->type == 1) {
    pbi->pup->type = 2;
    SwapSourceAndDest(pbi);
    SendPup(pbi);
    echoPkts += 1;
    if (!speedy) PutChar('$');
    };
  else ReleasePBI(pbi);
  };

static SwapSourceAndDest(pbi)
  struct PBI *pbi;
  {
  struct Port temp;
  MoveBlock(&temp, &pbi->pup->sPort, lenPort);
  MoveBlock(&pbi->pup->sPort, &pbi->pup->dPort, lenPort);
  MoveBlock(&pbi->pup->dPort, &temp, lenPort);
  };