-- File: DeviceInfo.mesa - last edit:
-- AOF                  3-Feb-88 18:04:40
-- HGM                  6-Aug-85 21:02:35
-- Copyright (C) 1984, 1985, 1988 by Xerox Corporation. All rights reserved. 

DIRECTORY
  Format USING [],  -- needed by Put.Date and friends
  Heap USING [systemZone],
  Menu USING [ItemObject, MCRType, Create, Instantiate],
  Process USING [Yield],
  Put USING [
    CR, Char, Date, HostNumber, LongDecimal, NetworkNumber, Number, Text],
  String USING [AppendChar, AppendNumber, AppendString],
  System USING [HostNumber, NetworkNumber],
  Time USING [Current],
  UserInput USING [GetDefaultWindow],
  Window USING [Handle],

  Buffer USING [],
  Driver USING [GetDeviceChain, Device],
  EthernetDriverFriends USING [EtherStatsInfo],
<<
  PhoneNetFriends USING [PhoneNetInfo, StatsPtrToStats],
  PhoneNetExtras USING [
    leafBytesSend, leafDupsFiltered, leafPktsSend,
    nsBytesSend, nsCongestion, nsDupsFiltered, nsTooGreedy,
    pupBytesSend, pupCongestion, pupDupsFiltered, pupTooGreedy],
>>
  Protocol1 USING [GetContext],
  PupRouterDefs USING [NetworkContext],
  RoutingTable USING [NetworkContext],
  SptpOps USING [StatsRecord, GetProtocolInfo],
  SptpProtocol USING [ProtocolObject];

DeviceInfo: PROGRAM
  IMPORTS
    Heap, Menu, Process, Put, String, Time, UserInput, Driver,
    Protocol1, SptpOps
  EXPORTS Buffer =
  BEGIN
  
  Device: PUBLIC TYPE = Driver.Device;

  z: UNCOUNTED ZONE = Heap.systemZone;

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

  ShowEthernet: PROCEDURE [wh: Window.Handle, network: Device] =
    BEGIN
    pup: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup];
    ns: RoutingTable.NetworkContext ← Protocol1.GetContext[network, ns];
    stats: LONG POINTER TO EthernetDriverFriends.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, pup.pupNetNumber, [8, FALSE, TRUE, 0]];
    Put.Text[wh, "#"L];
    Put.Number[wh, pup.pupHostNumber, [8, FALSE, TRUE, 0]];
    Put.Text[wh, "#, NS net "L];
    PutNetNumbers[wh, ns.netNumber];
    Put.CR[wh];
    IF stats = NIL THEN RETURN;
    Put.Text[wh, "Rcv: pkts "L];
    Put.LongDecimal[wh, stats.packetsRecv];
    Put.Text[wh, ", words "L];
    Put.LongDecimal[wh, stats.wordsRecv];
    Put.Text[wh, ", bad "L];
    Put.LongDecimal[wh, stats.badRecvStatus];
    Put.Text[wh, ", missed "L];
    Put.LongDecimal[wh, stats.packetsMissed];
    Put.CR[wh];
    IF stats.badRecvStatus # 0 OR stats.okButDribble # 0 THEN
      BEGIN
      Put.Text[wh, "  crc "L];
      Put.LongDecimal[wh, stats.badCrc];
      Put.Text[wh, ", bad alignment but ok crc "L];
      Put.LongDecimal[wh, stats.badAlignmentButOkCrc];
      Put.Text[wh, ", crc and bad alignment "L];
      Put.LongDecimal[wh, stats.crcAndBadAlignment];
      Put.CR[wh];
      Put.Text[wh, "  ok but dribble "L];
      Put.LongDecimal[wh, stats.okButDribble];
      Put.Text[wh, ", too long "L];
      Put.LongDecimal[wh, stats.packetTooLong];
      Put.Text[wh, ", overrun "L];
      Put.LongDecimal[wh, stats.overrun];
      Put.Text[wh, ", idle "L];
      Put.LongDecimal[wh, stats.idleInput];
      Put.CR[wh];
      END;
    Put.Text[wh, "Xmit: pkts "L];
    Put.LongDecimal[wh, stats.packetsSent];
    Put.Text[wh, ", words "L];
    Put.LongDecimal[wh, stats.wordsSent];
    Put.Text[wh, ", bad "L];
    Put.LongDecimal[wh, stats.badSendStatus];
    Put.CR[wh];
    IF stats.badSendStatus # 0 OR stats.tooManyCollisions # 0 THEN
      BEGIN
      Put.Text[wh, "  underrun "L];
      Put.LongDecimal[wh, stats.underrun];
      Put.Text[wh, ", stuck "L];
      Put.LongDecimal[wh, stats.stuckOutput];
      Put.Text[wh, ", too many collisions "L];
      Put.LongDecimal[wh, stats.tooManyCollisions];
      Put.CR[wh];
      END;
    Put.Text[wh, "Lds:"L];
    FOR i: CARDINAL IN [0..16) DO
      Put.Char[wh, ' ]; Put.LongDecimal[wh, stats.loadTable[i]]; ENDLOOP;
    Put.CR[wh];
    END;

  ShowPhoneNet: PROCEDURE [wh: Window.Handle, network: Device] =
    BEGIN
    info: SptpProtocol.ProtocolObject;
    pup: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup];
    ns: RoutingTable.NetworkContext ← Protocol1.GetContext[network, ns];
    stats: LONG POINTER TO SptpOps.StatsRecord ← network.stats;
    SptpOps.GetProtocolInfo[network, @info];
    PrintHeader[wh, "PhoneNet"L, FALSE];
    Put.Text[wh, " Statistics for "L];
    Put.Number[wh, pup.pupNetNumber, [8, FALSE, TRUE, 0]];
    Put.Text[wh, "#"L];
    Put.Number[wh, pup.pupHostNumber, [8, FALSE, TRUE, 0]];
    Put.Text[wh, "#, NS net "L];
    PutNetNumbers[wh, ns.netNumber];
    Put.Text[wh, ", Line "L];
    Put.LongDecimal[wh, network.lineNumber];
    Put.Text[wh, ", "L];
    Put.LongDecimal[wh, network.lineSpeed];
    Put.Text[wh, "KB"L];
    IF info.state # data THEN Put.Text[wh, "  Down"L]
    ELSE
      BEGIN
      Put.CR[wh];
      Put.Text[wh, "Up to "L];
      PutHostNumbers[wh, info.him];
      END;
    Put.CR[wh];
    Put.Text[wh, "Recv: pkts "L];
    Put.LongDecimal[wh, stats.pktsReceived];
    Put.Text[wh, ", bytes "L];
    Put.LongDecimal[wh, stats.bytesReceived];
    Put.CR[wh];
    Put.Text[wh, "  Bad crc "L];
    Put.LongDecimal[wh, stats.checksumError];
    Put.Text[wh, ", data lost "L];
    Put.LongDecimal[wh, stats.dataLost];
    Put.Text[wh, ", device error "L];
    Put.LongDecimal[wh, stats.deviceError];
    Put.CR[wh];
    Put.Text[wh, "Send: pkts "L];
    Put.LongDecimal[wh, stats.packetsSent];
    Put.Text[wh, ", bytes "L];
    Put.LongDecimal[wh, stats.bytesSent];
    Put.CR[wh];
<<
    IF stats.stats[sendErrorBadStatus] # 0 OR stats.stats[queueTooOld] # 0 THEN {
      Put.Text[wh, "  Bad "L];
      Put.LongDecimal[wh, stats.stats[sendErrorBadStatus]];
      Put.Text[wh, ", stuck "L];
      Put.LongDecimal[wh, stats.stats[queueTooOld]];
      Put.CR[wh]; };
    Put.Text[wh, "  Queue too long "L];
    Put.LongDecimal[wh, stats.stats[congestion]];
    Put.Text[wh, ", NS "L];
    Put.LongDecimal[wh, stats.stats[PhoneNetExtras.nsCongestion]];
    Put.Text[wh, "  Pup "L];
    Put.LongDecimal[wh, stats.stats[PhoneNetExtras.pupCongestion]];
    Put.CR[wh];
    Put.Text[wh, "  Conn too greedy "L];
    Put.LongDecimal[wh, stats.stats[connTooGreedy]];
    Put.Text[wh, ", NS "L];
    Put.LongDecimal[wh, stats.stats[PhoneNetExtras.nsTooGreedy]];
    Put.Text[wh, ", Pup "L];
    Put.LongDecimal[wh, stats.stats[PhoneNetExtras.pupTooGreedy]];
    Put.CR[wh];
    IF stats.stats[PhoneNetExtras.nsDupsFiltered] # 0 THEN {
      Put.Text[wh, "    NS duplicates discarded: "L];
      Put.LongDecimal[wh, stats.stats[PhoneNetExtras.nsDupsFiltered]];
      Put.CR[wh]; };
    IF stats.stats[PhoneNetExtras.pupDupsFiltered] # 0 THEN {
      Put.Text[wh, "    BSP probes/duplicates discarded: "L];
      Put.LongDecimal[wh, stats.stats[PhoneNetExtras.pupDupsFiltered]];
      Put.CR[wh]; };
    IF stats.stats[PhoneNetExtras.leafDupsFiltered] # 0 THEN {
      Put.Text[wh, "    Leaf duplicates discarded: "L];
      Put.LongDecimal[wh, stats.stats[PhoneNetExtras.leafDupsFiltered]];
      Put.CR[wh]; };
>>
    END;

  PutHostNumbers: PROCEDURE [wh: Window.Handle, net: System.HostNumber] =
    BEGIN
    Put.HostNumber[wh, net, productSoftware];
    Put.Text[wh, "="L];
    Put.HostNumber[wh, net, octal];
    END;
      
  PutNetNumbers: PROCEDURE [wh: Window.Handle, net: System.NetworkNumber] =
    BEGIN
    Put.NetworkNumber[wh, net, productSoftware];
    Put.Text[wh, "="L];
    Put.NetworkNumber[wh, net, octal];
    END;
      
  PrintHeader: PROCEDURE [wh: Window.Handle, s: LONG 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
    Items: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF Menu.ItemObject];
    items: LONG POINTER TO Items;
    firstDevice: Device ← Driver.GetDeviceChain[];
    devices: CARDINAL ← 0;
    FOR network: Device ← firstDevice, network.next UNTIL network = NIL DO
      devices ← devices + 1;
      ENDLOOP;
    items ← z.NEW[Items[devices]];
    devices ← 0;
    FOR network: Device ← firstDevice, network.next UNTIL network = NIL DO
      context: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup];
      tag: STRING = [30];
      new: LONG STRING;
      SELECT network.device FROM
        ethernetOne => String.AppendString[tag, "Ether1"L];
        ethernet => String.AppendString[tag, "Ether"L];
        phonenet => String.AppendString[tag, "PhoneNet"L];
        ENDCASE => ERROR;
      String.AppendChar[tag, '-];
      String.AppendNumber[tag, context.pupNetNumber, 8];
      new ← z.NEW[StringBody[tag.length]];
      String.AppendString[new, tag];
      items[devices] ← [new, DoMenu];
      devices ← devices + 1;
      ENDLOOP;
    Menu.Instantiate[
      Menu.Create[DESCRIPTOR[items, devices], "DeviceInfo"],
      UserInput.GetDefaultWindow[]];
    END;


  -- Initialization

  SetupDeviceMenu[];
  END.