-- Copyright (C) 1983, 1985  by Xerox Corporation. All rights reserved. 
-- Breather.mesa, HGM,  6-Aug-85 21:02:18

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],
  Protocol1 USING [GetContext],
  PupRouterDefs USING [NetworkContext],
  Stats USING [StatIncr];

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

  Network: PUBLIC TYPE = Driver.Network;

  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
	context: PupRouterDefs.NetworkContext ← Protocol1.GetContext[network, pup];
        IF context = NIL THEN LOOP;
        IF network.device # ethernetOne THEN LOOP;
        b ← Buffer.GetBuffer[vagrant, 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: context.pupHostNumber,
          ethernetOneType: breathOfLife]];
        network.sendRawBuffer[b];
        Stats.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.