-- File: DeviceInfo.mesa,  Last Edit: HGM  February 5, 1981  5:57 PM

DIRECTORY
  Format USING [], -- needed by Put.Date and friends
  Menu USING [ItemObject, MCRType, Create, Instantiate],
  Process USING [Yield],
  Put USING [CR, Char, Date, Line, LongDecimal, LongNumber, Number, Text],
  String USING [AppendChar, AppendNumber, AppendString],
  Storage USING [CopyString, Node],
  Time USING [Current],
  UserInput USING [GetDefaultWindow],
  Window USING [Handle],

  AltoEthernetDefs USING [EtherStatsInfo],
  AltoSlaDefs,
  AltoPRDefs,
  DriverDefs USING [GetDeviceChain, Network],
  PupDefs USING [GetFreePupBuffer, ReturnFreePupBuffer, PupBuffer];

DeviceInfo: PROGRAM
  IMPORTS
    Menu, Process, Put, String, Storage, Time, UserInput, DriverDefs, PupDefs =
  BEGIN

  items: POINTER TO ARRAY [0..0) OF Menu.ItemObject;

  DoMenu: Menu.MCRType =
    BEGIN
    firstNetwork: DriverDefs.Network ← DriverDefs.GetDeviceChain[];
    device: CARDINAL ← 0;
    FOR network: DriverDefs.Network ← firstNetwork, network.next UNTIL network =
      NIL DO
      IF index = device THEN
	BEGIN
	SELECT network.device FROM
	  ethernet, ethernetOne => ShowEthernet[NIL, network];
	  sla => ShowSla[NIL, network];
	  packetradio => ShowPacketRadio[NIL, network];
	  phonenet => ShowPhoneNet[NIL, network];
	  ENDCASE => ERROR;
	RETURN;
	END;
      device ← device + 1;
      ENDLOOP;
    END;

  ShowEthernet: PROCEDURE [wh: Window.Handle, network: DriverDefs.Network] =
    BEGIN
    stats: LONG POINTER TO AltoEthernetDefs.EtherStatsInfo ← network.stats;
    PrintHeader[wh, "Ethernet"L, FALSE];
    IF network.device = ethernetOne THEN Put.Text[wh, "One"L];
    Put.Text[wh, " Statistics for "L];
    Put.Number[wh, network.netNumber.b, [8, FALSE, TRUE, 0]];
    Put.Line[wh, "##:"L];
    Put.Text[wh, "Rcv: good "L];
    Put.LongDecimal[wh, stats.packetsRecv];
    Put.Text[wh, ", bad "L];
    Put.LongDecimal[wh, stats.badRecvStatus];
    Put.Text[wh, ", off "L];
    Put.LongDecimal[wh, stats.inputOff];
    Put.Text[wh, "; Xmit: good "L];
    Put.LongDecimal[wh, stats.packetsSent];
    Put.Text[wh, ", bad "L];
    Put.LongDecimal[wh, stats.badSendSatus];
    Put.Text[wh, "; Overrun "L];
    Put.LongDecimal[wh, stats.overruns];
    Put.CR[wh];
    Put.Text[wh, "Lds:"L];
    FOR i: CARDINAL IN [0..16) DO
      Put.Char[wh, ' ]; Put.LongDecimal[wh, stats.loadTable[i]]; ENDLOOP;
    Put.Text[wh, "; Ovf: "L];
    Put.LongDecimal[wh, stats.loadTable[16]];
    Put.CR[wh];
    END;

  ShowSla: PROCEDURE [wh: Window.Handle, network: DriverDefs.Network] =
    BEGIN OPEN AltoSlaDefs;
    p: LONG POINTER ← network.stats;
    routingTable: LONG POINTER TO ARRAY SlaHost OF RoutingTableEntry;
    lineInfo: LONG POINTER TO ARRAY Line OF LineInfoBlock;
    activeLines: Line;
    activeLines ← p↑;
    p ← 8 + p + maxLine*SIZE[LineTableEntry];
    routingTable ← p;
    p ← p + maxSlaHost*SIZE[RoutingTableEntry];
    lineInfo ← p;
    BEGIN
    D6: PROCEDURE [n: CARDINAL] =
      BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 6]]; END;
    LD8: PROCEDURE [n: LONG CARDINAL] =
      BEGIN Put.LongNumber[wh, n, [10, FALSE, TRUE, 8]]; END;
    LD12: PROCEDURE [n: LONG CARDINAL] =
      BEGIN Put.LongNumber[wh, n, [10, FALSE, TRUE, 12]]; END;
    lib: LONG POINTER TO LineInfoBlock;
    Put.CR[wh];
    PrintHeader[wh, "SLA Line Statistics:"L];
    Put.Line[
      wh,
      "        ---Packets---    --------Bytes-------    -----------Errors---------
Ln To    Sent    Recv        Sent        Recv    Dn  Ovrn   CRC  Sync Cntrl  State"L];
    FOR line: Line IN [0..activeLines) DO
      lib ← @lineInfo[line];
      Put.Number[wh, line, [8, FALSE, TRUE, 2]];
      IF lib.partner = noPartner THEN Put.Text[wh, "  ?"L]
      ELSE Put.Number[wh, lib.partner, [8, FALSE, TRUE, 3]];
      LD8[lib.packetsSent];
      LD8[lib.packetsRecv];
      LD12[lib.bytesSent];
      LD12[lib.bytesRecv];
      D6[lib.deaths];
      D6[lib.overrun];
      D6[lib.crcErrors];
      D6[lib.syncErrors];
      D6[lib.controlErrors];
      Put.Text[wh, "  "L];
      SELECT lib.state FROM
	up => Put.Line[wh, "Up"L];
	down => Put.Line[wh, "Down"L];
	loopedBack => Put.Line[wh, "Looped"L];
	missing => Put.Line[wh, "Missing"L];
	halfUp => Put.Line[wh, "Half Up"L];
	passwordOk => Put.Line[wh, "Password OK"L];
	needPassword => Put.Line[wh, "Need Password"L];
	badPassword => Put.Line[wh, "Bad Password"L];
	ENDCASE => Put.Line[wh, "  ??"L];
      DoSomeYields[];
      ENDLOOP;
    END;
    BEGIN
    O4: PROCEDURE [n: CARDINAL] =
      BEGIN Put.Number[wh, n, [8, FALSE, TRUE, 4]]; END;
    D5: PROCEDURE [n: CARDINAL] =
      BEGIN Put.Number[wh, n, [10, FALSE, TRUE, 5]]; END;
    k: CARDINAL ← 0;
    rte: LONG POINTER TO AltoSlaDefs.RoutingTableEntry;
    Put.Line[
      wh,
      "
Routing Table:
Host Line Hops    Host Line Hops    Host Line Hops    Host Line Hops"L];
    FOR host: AltoSlaDefs.SlaHost IN AltoSlaDefs.SlaHost DO
      rte ← @routingTable[host];
      IF rte.hops = AltoSlaDefs.longHop THEN LOOP;
      IF k # 0 THEN Put.Text[wh, "    "L];
      O4[host];
      D5[rte.line];
      D5[rte.hops];
      IF (k ← k + 1) = 4 THEN BEGIN Put.CR[wh]; k ← 0; END;
      ENDLOOP;
    IF k # 0 THEN Put.CR[wh];
    END;
    END;

  ShowPacketRadio: PROCEDURE [wh: Window.Handle, network: DriverDefs.Network] =
    BEGIN
    LD10: PROCEDURE [n: LONG CARDINAL] =
      BEGIN Put.LongNumber[wh, n, [10, FALSE, TRUE, 10]]; END;
    b: PupDefs.PupBuffer ← PupDefs.GetFreePupBuffer[];
    p: LONG POINTER TO AltoPRDefs.PRStatsEntry ← LOOPHOLE[@b.pupWords[1]];
    [] ← network.pupStats[b, network];
    PrintHeader[wh, "Packet Radio Statistics:"L];
    Put.Line[
      wh, "           Pkts    Alives     One-F     Two-F   Three-F     Words"L];
    Put.Text[wh, "Sent:"];
    LD10[p.packetsSent];
    LD10[p.imAliveSent];
    LD10[p.oneFragPupSent];
    LD10[p.twoFragPupSent];
    LD10[p.threeFragPupSent];
    LD10[p.wordsSent];
    Put.CR[wh];
    Put.Text[wh, "Recv:"];
    LD10[p.packetsReceived];
    LD10[p.imAliveReceived];
    LD10[p.oneFragPupRcvd];
    LD10[p.twoFragPupRcvd];
    LD10[p.threeFragPupRcvd];
    LD10[p.wordsReceived];
    Put.CR[wh];
    Put.CR[wh];
    LD10[p.topsSent];
    Put.Text[wh, "  Tops Sent "L];
    LD10[p.inputFilter];
    Put.Text[wh, "  Input Fltr"L];
    LD10[p.outputPacketsDiscarded];
    Put.Line[wh, "  Out Disc"L];
    LD10[p.assemblyTimeout];
    Put.Text[wh, "  Assy T-O  "L];
    LD10[p.assemblyOverflow];
    Put.Text[wh, "  Assy Ovfl "L];
    LD10[p.transferTimeout];
    Put.Line[wh, "  Xfer T-O"L];
    LD10[p.oldPackets];
    Put.Text[wh, "  Old Pkts  "L];
    LD10[p.skippedPackets];
    Put.Text[wh, "  Skipped   "L];
    LD10[p.sequencerResets];
    Put.Line[wh, "  Seq Reset"L];
    Put.Text[wh, "PR Host Status: "];
    FOR i: CARDINAL IN [0..p.maxHosts) DO
      IF i # 0 THEN Put.Char[wh, ',];
      Put.Text[wh, IF p.hostsUp[i] THEN " up" ELSE " down"];
      ENDLOOP;
    Put.CR[wh];
    PupDefs.ReturnFreePupBuffer[b];
    END;

  ShowPhoneNet: PROCEDURE [wh: Window.Handle, network: DriverDefs.Network] =
    BEGIN Put.Text[wh, "mumble"L]; Put.CR[wh]; END;

  PrintHeader: PROCEDURE [wh: Window.Handle, s: STRING, cr: BOOLEAN ← TRUE] =
    BEGIN
    Put.CR[wh];
    Put.Date[wh, Time.Current[], dateTime];
    Put.Text[wh, "  "L];
    Put.Text[wh, s];
    IF cr THEN Put.CR[wh];
    END;

  DoSomeYields: PROCEDURE =
    BEGIN THROUGH [0..100) DO Process.Yield[]; ENDLOOP; END;


  SetupDeviceMenu: PUBLIC PROCEDURE =
    BEGIN
    firstNetwork: DriverDefs.Network ← DriverDefs.GetDeviceChain[];
    devices: CARDINAL ← 0;
    FOR network: DriverDefs.Network ← firstNetwork, network.next UNTIL network =
      NIL DO devices ← devices + 1; ENDLOOP;
    items ← Storage.Node[devices*SIZE[Menu.ItemObject]];
    devices ← 0;
    FOR network: DriverDefs.Network ← firstNetwork, network.next UNTIL network =
      NIL DO
      tag: STRING = [30];
      SELECT network.device FROM
	ethernetOne => String.AppendString[tag, "Ether1"L];
	ethernet => String.AppendString[tag, "Ether"L];
	sla => String.AppendString[tag, "SLA"L];
	packetradio => String.AppendString[tag, "Radio"L];
	phonenet => String.AppendString[tag, "PhoneNet"L];
	ENDCASE => ERROR;
      String.AppendChar[tag, '-];
      String.AppendNumber[tag, network.netNumber.b, 8];
      items[devices] ← [Storage.CopyString[tag], DoMenu];
      devices ← devices + 1;
      ENDLOOP;
    Menu.Instantiate[
      Menu.Create[DESCRIPTOR[items, devices], "DeviceInfo"],
      UserInput.GetDefaultWindow[]];
    END;


  -- Initialization

  SetupDeviceMenu[];
  END.