-- File: GateParameterTajo.mesa - last edit:
-- AOF                  3-Feb-88 16:29:02
-- HGM                  5-Oct-85 20:07:40
-- WIrish              22-Jul-86  9:09:55
-- Copyright (C) 1984, 1985, 1988 by Xerox Corporation. All rights reserved. 

DIRECTORY
  CmFile USING [Handle, TableError],
  Format USING [NetworkNumber],
  HeraldWindow USING [window],
  Process USING [Priority, priorityForeground],
  Put USING [NetworkNumber, Number, Text],
  Runtime USING [GetBuildTime],
  String USING [AppendChar, AppendDecimal, AppendNumber, AppendString],
  StringLookUp USING [noMatch, TableDesc],
  System USING [
    AdjustGreenwichMeanTime, GreenwichMeanTime, NetworkNumber, nullNetworkNumber],
  Time USING [Append, Packed, Unpack, Unpacked],
  Token USING [
    Boolean, Decimal, FreeStringHandle, FreeTokenString, Handle, Item,
    NetworkNumber, Octal, StringToHandle, SyntaxError],
  ToolWindow USING [Deactivate],

  Buffer USING [DeviceType],
  BufferOps USING [Defaults, GetDefaults, SetDefaults],
  Driver USING [GetDeviceChain, Device],
  Protocol1 USING [Family, GetContext, GetFamilyUnit],
  PupDefs USING [PupPackageMake, SmashMyHostNumber],
  PupRouterDefs USING [NetworkContext],
  Router USING [SetNetworkID],
  RoutingTable USING [NetworkContext],
  
  GateDefs USING [typescript],
  Indirect USING [Close, NextValue, OpenSection],
  MicrocodeVersion USING [VERSION, VersionResult],
  PhoneCreate USING [CreateSimplePhoneNet],
  RoutingFudges USING [SetNSFudge, SetPupFudge],
  Trouble USING [Bug, WrapTypescriptFile];

GateParameterTajo: PROGRAM
  IMPORTS
    CmFile, Format, HeraldWindow, Put, Process, Runtime,
    String, System,
    Time, Token, ToolWindow,
    BufferOps, Driver, GateDefs, Indirect,
    Protocol1, PupDefs, Router, MicrocodeVersion, PhoneCreate, RoutingFudges, Trouble
  EXPORTS Buffer, GateDefs =
  BEGIN

  Device: PUBLIC TYPE = Driver.Device;

  PrintHost: PROCEDURE [
    name: LONG STRING, board, pupNet: CARDINAL, nsNet: System.NetworkNumber] =
    BEGIN
    Put.Text[NIL, name];
    IF board # LAST[CARDINAL] THEN
      BEGIN Put.Text[NIL, " number "L]; Put.Number[NIL, board, [8, FALSE, TRUE, 0] ]; END;
    Put.Text[NIL, " is Pup network "L];
    Put.Number[NIL, pupNet, [8, FALSE, TRUE, 0] ];
    Put.Text[NIL, " and NS network "L];
    Put.NetworkNumber[NIL, nsNet, octal];
    Put.Text[NIL, " ("L];
    Put.NetworkNumber[NIL, nsNet, productSoftware];
    Put.Text[NIL, ").\n"L];
    END;

  ScanParameterFile: PUBLIC PROCEDURE RETURNS [
    priority: Process.Priority ← Process.priorityForeground,
    disableNSRouting: BOOLEAN ← FALSE] =
    BEGIN
    cmFile: CmFile.Handle;
    Option: TYPE = MACHINE DEPENDENT{
      ethernetOne(0), ethernet, leasedLine, pupHostNumber, buffers,
      priority, typescript, deactivateHerald, disableNSRouting, extraPupHops,
      extraNsHops, extraHops, noMatch(StringLookUp.noMatch)};
    DefinedOption: TYPE = Option [ethernetOne..extraHops];
    CheckType: PROCEDURE [h: CmFile.Handle, table: StringLookUp.TableDesc]
      RETURNS [index: CARDINAL] = Indirect.NextValue;
    MyNextValue: PROCEDURE [
      h: CmFile.Handle,
      table: LONG DESCRIPTOR FOR ARRAY DefinedOption OF LONG STRING]
      RETURNS [index: Option] = LOOPHOLE[CheckType];
    optionTable: ARRAY DefinedOption OF LONG STRING ← [
      ethernetOne: "EthernetOne"L, ethernet: "Ethernet"L,
      leasedLine: "Leased Line"L,
      pupHostNumber: "Pup Host Number"L, buffers: "Buffers"L,
      priority: "Priority"L, typescript: "Typescript"L,
      deactivateHerald: "Deactivate Herald Window"L,
      disableNSRouting: "Disable NS Routing"L,
      extraPupHops: "Extra PUP Hops"L,
      extraNsHops: "Extra NS Hops"L,
      extraHops: "Extra Hops"L];
    leasedLines: CARDINAL ← 0;

    cmFile ← Indirect.OpenSection["Gateway"L];
    IF cmFile = NIL THEN
      BEGIN
      Message["Can't find [Gateway] section in Parameter file"L];
      RETURN;
      END;

    DO
      option: Option;
      option ← MyNextValue[cmFile, DESCRIPTOR[optionTable] !
        CmFile.TableError =>
          BEGIN
	  IF name[0] # '; THEN Message["Unrecognized parameter: ", name];
	  RETRY;
	  END];
      SELECT option FROM
        noMatch => EXIT;
        ethernetOne =>  -- <board> <Pup Net> <NS net> (octal) 
          BEGIN
          board: CARDINAL ← Token.Decimal[cmFile];
          pupNet: CARDINAL ← Token.Octal[cmFile];
          nsNet: System.NetworkNumber ← Token.NetworkNumber[cmFile, octal];
	  MakeSurePupIsOn[];
          SetPupNetworkID[board, ethernetOne, pupNet];
	  IF nsNet # System.nullNetworkNumber THEN
	    BEGIN
            CheckNSNetworkID[board, ethernetOne, nsNet];
            [] ← Router.SetNetworkID[board, ethernetOne, nsNet];
	    END;
          PrintHost["EthernetOne"L, board, pupNet, nsNet];
          END;
        ethernet =>  -- <board> <Pup Net> <NS net> (octal) 
          BEGIN
          board: CARDINAL ← Token.Decimal[cmFile];
          pupNet: CARDINAL ← Token.Octal[cmFile];
          nsNet: System.NetworkNumber ← Token.NetworkNumber[cmFile, octal];
	  MakeSurePupIsOn[];
          SetPupNetworkID[board, ethernet, pupNet];
	  IF nsNet # System.nullNetworkNumber THEN
	    BEGIN
            CheckNSNetworkID[board, ethernet, nsNet];
            [] ← Router.SetNetworkID[board, ethernet, nsNet];
	    END;
          PrintHost["Ethernet"L, board, pupNet, nsNet];
          END;
        leasedLine =>  -- <line number> <Pup Net> <NS net> (octal) 
          BEGIN
          line: WORD ← Token.Octal[cmFile];
          pupNet: CARDINAL ← Token.Octal[cmFile];
          nsNet: System.NetworkNumber ← Token.NetworkNumber[cmFile, octal];
	  MakeSurePupIsOn[];
          leasedLines ← leasedLines + 1;
	  PhoneCreate.CreateSimplePhoneNet[line, pupNet, nsNet];
          SetPupNetworkID[leasedLines, phonenet, pupNet];
	  IF nsNet # System.nullNetworkNumber THEN
	    BEGIN
            CheckNSNetworkID[leasedLines, phonenet, nsNet];
            [] ← Router.SetNetworkID[leasedLines, phonenet, nsNet];
	    END;
          PrintHost["The Phone Line (NS Mode)"L, leasedLines, pupNet, nsNet];
          END;
        pupHostNumber =>
          BEGIN
          me: CARDINAL ← Token.Octal[cmFile];
          PupDefs.SmashMyHostNumber[me];
          MessageOctal["Set my Pup Host Number to "L, me];
          END;
        buffers =>  -- <number> (decimal)
          BEGIN
	  defaults: ARRAY BufferOps.Defaults OF CARDINAL ← BufferOps.GetDefaults[];
          buffers: CARDINAL ← Token.Decimal[cmFile];
	  defaults[bias] ← defaults[bias] + buffers;
          BufferOps.SetDefaults[defaults];
          MessageDecimal["Set number of buffers to "L, buffers];
          END;
        priority =>  -- <priority> (decimal)
          BEGIN
          priority ← Token.Decimal[cmFile];
          MessageDecimal["Priority will be "L, priority];
          END;
        typescript =>  -- <pages>
          BEGIN
          pages: CARDINAL ← Token.Decimal[cmFile];
          Trouble.WrapTypescriptFile[GateDefs.typescript, pages];
          MessageDecimal[
            "Typescript file will be trimmed at "L, pages, " pages"L];
          END;
        deactivateHerald =>  -- <boolean>
          BEGIN
          IF Token.Boolean[cmFile] THEN
            BEGIN
            Message["Deactivating Herald Window"L];
            [] ← ToolWindow.Deactivate[HeraldWindow.window];
            END
          ELSE Message["Didn't deactivate Herald Window"L];
          END;
        disableNSRouting =>  -- <boolean>
          BEGIN
          IF Token.Boolean[cmFile] THEN
            BEGIN
            Message["Deactivating NS Router"L];
	    disableNSRouting ← TRUE;
            END
          ELSE Message["Didn't deactivate NS Router"L];
          END;
        extraPupHops =>  -- <decimal>
         BEGIN
	  SetExtraPupHops[Token.Decimal[cmFile]];
          END;
        extraNsHops =>  -- <decimal>
         BEGIN
	  SetExtraNsHops[Token.Decimal[cmFile]];
          END;
        extraHops =>  -- <boolean> or <decimal>
 	              -- FALSE -> 0, TRUE -> 1
         BEGIN
	  hopsToAdd: CARDINAL ← 0;
	  item: LONG STRING ← Token.Item[cmFile];
	  th: Token.Handle ← Token.StringToHandle[item];
	  th1: Token.Handle ← Token.StringToHandle[item];
          IF Token.Boolean[th ! Token.SyntaxError => BEGIN
	       hopsToAdd ← Token.Decimal[th1];
	       CONTINUE;
	       END;]
	     THEN hopsToAdd ← 1;
	  [] ← Token.FreeStringHandle[th];
	  [] ← Token.FreeStringHandle[th1];
	  [] ← Token.FreeTokenString[item];
	  SetExtraPupHops[hopsToAdd];
	  SetExtraNsHops[hopsToAdd];
          END;

        ENDCASE => ERROR;
      ENDLOOP;

    Indirect.Close[cmFile];

    END;

  SetExtraPupHops: PROCEDURE [hops: CARDINAL] =
    BEGIN
    IF hops > 0 THEN
       BEGIN
       MessageDecimal["Setting Extra PUP Hops to "L, hops];
       RoutingFudges.SetPupFudge[hops];
       END
    ELSE Message["There are no Extra PUP Hops"L];
    END;

  SetExtraNsHops: PROCEDURE [hops: CARDINAL] =
    BEGIN
    IF hops > 0 THEN
       BEGIN
       MessageDecimal["Setting Extra NS Hops to "L, hops];
       RoutingFudges.SetNSFudge[hops];
       END
    ELSE Message["There are no Extra NS Hops"L];
    END;

  MessageDecimal: PROCEDURE [
    one: LONG STRING, num: CARDINAL, two, three: LONG STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    String.AppendDecimal[text, num];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    String.AppendChar[text, '.];
    String.AppendChar[text, '\n];
    LogString[text];
    END;

  MessageOctal: PROCEDURE [
    one: LONG STRING, num: CARDINAL, two, three: LONG STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    String.AppendNumber[text, num, 8];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    String.AppendChar[text, '.];
    String.AppendChar[text, '\n];
    LogString[text];
    END;

  Message: PROCEDURE [one, two, three: LONG STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    String.AppendChar[text, '.];
    String.AppendChar[text, '\n];
    LogString[text];
    END;

  LogString: PROCEDURE [text: LONG STRING] = BEGIN Put.Text[NIL, text]; END;

  PrintTajoVersion: PROCEDURE =
    BEGIN
    temp: STRING = [100];
    packed: Time.Packed;
    unpacked: Time.Unpacked;
    String.AppendString[temp, "Running on Tajo of "L];
    Time.Append[temp, Time.Unpack[Runtime.GetBuildTime[]], TRUE];
    String.AppendString[temp, " = "L];
    packed ← Runtime.GetBuildTime[];
    unpacked ← Time.Unpack[packed, [useThese[[west, 0, 0, 366, 366]]]];
    Time.Append[temp, unpacked, TRUE];
    String.AppendString[temp, ".\n"L];
    LogString[temp];
    END;

  PrintMicrocodeInfo: PROCEDURE =
    BEGIN
    CatchKrock: PROCEDURE RETURNS [MicrocodeVersion.VersionResult] =
      BEGIN
      RETURN[MicrocodeVersion.VERSION[]];
      END;
    temp: STRING = [200];
    version: MicrocodeVersion.VersionResult ← CatchKrock[ ! ANY => GOTO NoVersion];
    when: System.GreenwichMeanTime ←  -- 0 => Jan 1, 1901
      System.AdjustGreenwichMeanTime[[0], version.releaseDate*86400];
    unpacked: Time.Unpacked;
    String.AppendString[temp, "This microcode was built on "L];
    unpacked ← Time.Unpack[when, [useThese[[west, 0, 0, 366, 366]]]];
    Time.Append[temp, unpacked, FALSE];
    temp.length ← temp.length - 9;  -- Discard time = " xx:xx:xx"
    String.AppendString[temp, ".\n"L];
    String.AppendString[temp, "This machine is a "L];
    String.AppendString[temp, 
      SELECT version.machineType FROM
        dolphin => "Dolphin"L,
        dorado => "Dorado"L,
        dandelion => "Dandelion"L,
        dicentra => "Dicentra"L,
	ENDCASE => "??"L];
    String.AppendString[temp, ".  FloatintPoint = "L];
    String.AppendString[temp, IF version.floatingPoint THEN "TRUE"L ELSE "FALSE"L];
    String.AppendString[temp, ", Cedar = "L];
    String.AppendString[temp, IF version.cedar THEN "TRUE"L ELSE "FALSE"L];
    String.AppendString[temp, ".\n"L];
    LogString[temp];
    EXITS NoVersion => LogString["This microcode won't tell me when it was built.\n"];
    END;

  turnedOnAlready: BOOL ← FALSE;
  MakeSurePupIsOn: PROCEDURE =
    BEGIN
    IF turnedOnAlready THEN RETURN;
    [] ← PupDefs.PupPackageMake[];
    turnedOnAlready ← TRUE;
    END;

  SetPupNetworkID: PROCEDURE [
    physicalOrder: CARDINAL, medium: Buffer.DeviceType, newNetID: CARDINAL] =
    BEGIN
    network: Device ← GetNthDevice[physicalOrder, medium];
    context: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup];
    family: Protocol1.Family ← Protocol1.GetFamilyUnit[pup];
    IF context.pupNetNumber # 0 AND context.pupNetNumber # newNetID THEN
      BEGIN
      text: STRING = [200];
      String.AppendString[text, "Wrong Pup network number.  Expected: "L];
      String.AppendNumber[text, newNetID, 8];
      String.AppendString[text, ", Found: "L];
      String.AppendNumber[text, context.pupNetNumber, 8];
      Trouble.Bug[text];
      END;
    context.pupNetNumber ← newNetID;
    family.stateChanged[network, context, add];
    END;

  CheckNSNetworkID: PROCEDURE [
    physicalOrder: CARDINAL, medium: Buffer.DeviceType,
    newNetID: System.NetworkNumber] =
    BEGIN
    ENABLE UNWIND => NULL;
    network: Device ← GetNthDevice[physicalOrder, medium];
    context: RoutingTable.NetworkContext ← Protocol1.GetContext[network, ns];
    IF context.netNumber # System.nullNetworkNumber AND context.netNumber # newNetID THEN
      BEGIN
      text: STRING = [200];
      String.AppendString[text, "Wrong NS network number.  Expected: "L];
      AppendNetNumbers[text, newNetID];
      String.AppendString[text, ", Found: "L];
      AppendNetNumbers[text, context.netNumber];
      Trouble.Bug[text];
      END;
    network ← NIL;  -- Compiler and Debugger don't cooperate
    END;

  AppendNetNumbers: PROCEDURE [string: LONG STRING, net: System.NetworkNumber] =
    BEGIN
    words: RECORD [a, b: WORD] = LOOPHOLE[net];
    AppendNetNumber[string, net];
    IF words.b < 256 THEN
      BEGIN
      String.AppendString[string, " ("L];
      AppendNetNumberOctal[string, net];
      String.AppendString[string, ")"L];
      END;
    END;

  AppendNetNumber: PROCEDURE [string: LONG STRING, net: System.NetworkNumber] =
    BEGIN
    Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
      BEGIN String.AppendString[string, s]; END;
    Format.NetworkNumber[Append, net, productSoftware];
    END;

  AppendNetNumberOctal: PROCEDURE [string: LONG STRING, net: System.NetworkNumber] =
    BEGIN
    Append: PROCEDURE [s: LONG STRING, clientData: LONG POINTER] =
      BEGIN String.AppendString[string, s]; END;
    Format.NetworkNumber[Append, net, octal];
    END;

  GetNthDevice: PROCEDURE [
    physicalOrder: CARDINAL, medium: Buffer.DeviceType]
    RETURNS [network: Device] =
    BEGIN
    i: CARDINAL ← 0;
    FOR network ← Driver.GetDeviceChain[], network.next UNTIL network = NIL DO
      IF network.device = medium THEN IF (i ← i + 1) = physicalOrder THEN RETURN;
      ENDLOOP;
    Trouble.Bug["Driver doesn't exist"L];
    network ← NIL;  -- Compiler and Debugger don't cooperate
    END;


  -- initialization
  PrintTajoVersion[];
  PrintMicrocodeInfo[];
  END.