-- Copyright (C) 1983, 1985  by Xerox Corporation. All rights reserved. 
-- EtherBooter.mesa, HGM,  6-Apr-85 12:07:35

DIRECTORY
  Boot USING [EthernetRequest],
  Device USING [Type],
  DeviceTypes USING [ethernet],
  Heap USING [systemZone],
  NSConstants USING [bootServerSocket],
  OthelloDefs USING [
    AbortingCommand, CommandProcessor, Confirm, GetName,
    IndexTooLarge, MyNameIs, ReadShortNumber, RegisterCommandProc],
  Runtime USING [CallDebugger],
  SpecialBooting USING [BootFromEthernet, BootFromEthernetOne],
  String USING [CopyToNewString],
  System USING [
    broadcastHostNumber, defaultSwitches, HostNumber,
    NetworkAddress, nullNetworkNumber, PowerOff, Switches, UpDown],
  TemporaryBooting USING [BootButton],
  Unformat USING [Error, HostNumber],
  
  PhoneFace USING [krockDeivceOffsetForBooting, phoneLine],
  Watchdog USING [Activate, Deactivate];

EtherBooter: PROGRAM
  IMPORTS
    Heap, OthelloDefs, Runtime, SpecialBooting, String, System,
    TemporaryBooting, Unformat,
    Watchdog =
  BEGIN
  
  bootFileNumber: LONG STRING;
  switches: LONG STRING ← NIL;
  
  EtherBoot: PROCEDURE [device: Device.Type] =
    BEGIN
    phone: BOOLEAN = device = PhoneFace.phoneLine;
    where: Boot.EthernetRequest;
    bfn: System.HostNumber;
    board: CARDINAL ← 0;
    address: System.NetworkAddress;
    krock: CARDINAL ← IF phone THEN PhoneFace.krockDeivceOffsetForBooting ELSE 0;
    OthelloDefs.GetName[
      IF phone THEN "Phone Boot from boot file number: "L
      ELSE "Ether Boot from boot file number: "L,
      @bootFileNumber];
    GetAddress[@bfn, bootFileNumber !
      Unformat.Error => OthelloDefs.AbortingCommand["Can't parse that one (No CH)"L]];
    OthelloDefs.GetName["Switches: "L, @switches];
    board ← OthelloDefs.ReadShortNumber[IF phone THEN "Line: " ELSE "Board: "L, 0, 3, board];
    OthelloDefs.Confirm[];
    address ← [
      net: System.nullNetworkNumber,
      host: System.broadcastHostNumber,
      socket: NSConstants.bootServerSocket];
    where ← [
      bfn: [LOOPHOLE[bfn]],
      address: address ];
    Watchdog.Activate[(IF phone THEN 10 ELSE 5)*60];
    SpecialBooting.BootFromEthernet[
      ethernetRequest: where, deviceOrdinal: krock+board, switches: DecodeSwitches[switches]];
    END;

  GetAddress: PROCEDURE [host: POINTER TO System.HostNumber, s: LONG STRING] =
    BEGIN
    host↑ ← Unformat.HostNumber[s, octal];
    END;

  PupEtherBoot: PROCEDURE =
    BEGIN
    bfn: CARDINAL;
    board: CARDINAL ← 0;
    bfn ← OthelloDefs.ReadShortNumber[
      "Pup Boot file number: "L, 0, CARDINAL.LAST, 140000B];
    board ← OthelloDefs.ReadShortNumber["Board: "L, 0, 3, board];
    OthelloDefs.Confirm[];
    Watchdog.Activate[5*60];
    SpecialBooting.BootFromEthernetOne[
      bootFileNumber: bfn, net: 0, host: 0, deviceOrdinal: board,
      switches: DecodeSwitches[switches]];
    END;

  DecodeSwitches: PUBLIC PROC [switchString: LONG STRING]
    RETURNS [switches: System.Switches ← System.defaultSwitches] =
    BEGIN
    escapeCount: CARDINAL ← 0;
    setUpDown: System.UpDown ← down;
    escapeChar: CHARACTER ← 0C;
    IF switchString = NIL THEN RETURN;
    FOR i: CARDINAL IN [0..switchString.length) DO
      c: CHARACTER = switchString[i];
      SELECT TRUE FROM
        c = '-, c = '~ => {
          IF setUpDown = up THEN BadSwitches[] ELSE {setUpDown ← up; LOOP}};
        c = '\\ => {
          IF escapeCount # 0 THEN BadSwitches[] ELSE {escapeCount ← 1; LOOP}};
        escapeCount = 1 => {
          SELECT c FROM
            'n, 'N, 'r, 'R => {switches['\n] ← setUpDown; escapeCount ← 0};
            't, 'T => {switches['\t] ← setUpDown; escapeCount ← 0};
            'b, 'B => {switches['\b] ← setUpDown; escapeCount ← 0};
            'f, 'F => {switches['\f] ← setUpDown; escapeCount ← 0};
            'l, 'L => {switches['\l] ← setUpDown; escapeCount ← 0};
            '\\ => {switches['\\] ← setUpDown; escapeCount ← 0};
            IN ['0..'7] => {
              escapeChar ← c - ('0 - 0C); escapeCount ← escapeCount + 1};
            ENDCASE => BadSwitches[];
          LOOP};
        escapeCount # 0 => {
          IF c NOT IN ['0..'7] THEN BadSwitches[];
          escapeChar ← (c - '0) + (escapeChar - 0C) * 8 + 0C;
          IF escapeChar > 377C THEN BadSwitches[];
          IF (escapeCount ← escapeCount + 1) = 4 THEN {
            switches[escapeChar] ← setUpDown; escapeCount ← 0};
          LOOP};
        ENDCASE => switches[c] ← setUpDown;
      -- fall through to here if normal set or escape set
      -- but not on seeing or while collecting escape
      setUpDown ← down;
      ENDLOOP;
    IF escapeCount # 0 THEN BadSwitches[];
    END;
  
  BadSwitches: PROCEDURE =
    BEGIN
    OthelloDefs.AbortingCommand["Bad Switches"L];
    END;


  Commands: PROCEDURE [index: CARDINAL] =
    BEGIN
    SELECT index FROM
      0 => 
        BEGIN
        SIGNAL OthelloDefs.MyNameIs[
	  myNameIs: "Boot Button"L,
	  myHelpIs: "Push the boot button"L];
        OthelloDefs.Confirm[];
	TemporaryBooting.BootButton[];
	END;
      1 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "Boot From Ethernet"L,
	  myHelpIs: "Load another program over the 10MB Ethernet"L];
	EtherBoot[DeviceTypes.ethernet];
	END;
      2 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "Boot From Phone Line"L,
	  myHelpIs: "Load another program over the Phone Line"L];
	EtherBoot[PhoneFace.phoneLine];
	END;
      3 =>
        BEGIN
        OthelloDefs.MyNameIs[
	  myNameIs: "Boot From Pup(3MB)"L,
	  myHelpIs: "Load another program over the 3MB Ethernet"L];
	PupEtherBoot[];
	END;
      4 =>
        BEGIN
        SIGNAL OthelloDefs.MyNameIs[
	  myNameIs: "Debug",
	  myHelpIs: "Call CoPilot"L];
        OthelloDefs.Confirm[];
	Watchdog.Deactivate[];
	Runtime.CallDebugger["Hi"L];
	END;
      5 =>
        BEGIN
        SIGNAL OthelloDefs.MyNameIs[
	  myNameIs: "Power Off",
	  myHelpIs: "Execute System.PowerOff"L];
        OthelloDefs.Confirm[];
	System.PowerOff[];
	END;
      ENDCASE => OthelloDefs.IndexTooLarge;
    END;
   
  commandProcessor: OthelloDefs.CommandProcessor ← [Commands];
  bootFileNumber ← String.CopyToNewString["25200002000", Heap.systemZone];  -- Setup Default
  OthelloDefs.RegisterCommandProc[@commandProcessor];
  END.....