-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- Breather.mesa, HGM,  5-Oct-83 20:26:19

DIRECTORY
  Inline USING [LongCOPY],
  Process USING [Detach, SetTimeout, MsecToTicks],
  
  Buffer USING [AccessHandle, Buffer, DestroyPool, GetBuffer, MakePool],
  BootServerDefs USING [statLife],
  DiskLessDefs USING [GetPointerToBootLoader],
  Driver USING [Network, GetDeviceChain],
  DriverTypes USING [ethernetOneBootLoaderHost, ethernetOneEncapsulationOffset],
  Stats USING [StatIncr];

Breather: MONITOR
  IMPORTS Inline, Process, Buffer, Driver, BootServerDefs, DiskLessDefs, Stats
  EXPORTS BootServerDefs =
  BEGIN OPEN Stats;

  breatherRunning, breatherStop: BOOLEAN ← FALSE;
  delay: CONDITION;

  -- Send BreathOfLife RAW Packet every 5 seconds or so
  EthernetBreather: ENTRY PROCEDURE =
    BEGIN
    pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 0];
    b: Buffer.Buffer;
    firstNetwork: Driver.Network = Driver.GetDeviceChain[];
    bootLoader: POINTER ← DiskLessDefs.GetPointerToBootLoader[];
    FOR network: Driver.Network ← firstNetwork, network.next UNTIL network =
      NIL DO
      IF network.device = ethernetOne THEN EXIT;
      REPEAT FINISHED => BEGIN breatherRunning ← FALSE; RETURN; END;
      ENDLOOP;
    UNTIL breatherStop DO
      WAIT delay;
      FOR network: Driver.Network ← firstNetwork, network.next UNTIL network =
        NIL DO
        IF network.device # ethernetOne THEN LOOP;
        b ← Buffer.GetBuffer[raw, pool, send];
        b.driver.length ← 256;
        -- the boot loader has the encapsulation in it already
        Inline.LongCOPY[
          from: bootLoader, nwords: 256,
          to: @b.encapsulation + DriverTypes.ethernetOneEncapsulationOffset];
        b.encapsulation ← [
          ethernetOne[
          etherSpare1:, etherSpare2:, etherSpare3:, etherSpare4:, etherSpare5:,
          translationWorked: TRUE,
          ethernetOneDest: DriverTypes.ethernetOneBootLoaderHost,
          ethernetOneSource: network.pupHostNumber,
          ethernetOneType: breathOfLife]];
        network.sendRawBuffer[b];
        StatIncr[BootServerDefs.statLife];
        ENDLOOP;
      ENDLOOP;
    breatherRunning ← FALSE;
    Buffer.DestroyPool[pool];
    END;

  BreatherOn: PUBLIC PROCEDURE =
    BEGIN
    breatherStop ← FALSE;
    breatherRunning ← TRUE;
    Process.Detach[FORK EthernetBreather[]];
    END;

  BreatherOff: PUBLIC ENTRY PROCEDURE =
    BEGIN
    pause: CONDITION;
    breatherStop ← TRUE;
    Process.SetTimeout[@pause, Process.MsecToTicks[100]];
    NOTIFY delay;
    WHILE breatherRunning DO WAIT pause; ENDLOOP;
    END;


  -- initialization

  Process.SetTimeout[@delay, Process.MsecToTicks[5000]];
  END.