-- File: Breather.mesa - last edit:
-- AOF                  3-Feb-88 13:12:06
-- HGM                  6-Aug-85 21:02:18
-- Copyright (C) 1983, 1985, 1988 by Xerox Corporation. All rights reserved. 

DIRECTORY
  Inline USING [LongCOPY],
  Process USING [Detach, SetTimeout, MsecToTicks],
  Buffer USING [AccessHandle, Buffer, DestroyPool, GetBuffer, MakePool],
  BootServerDefs USING [statLife],
  DiskLessDefs USING [GetPointerToBootLoader],
  Driver USING [Device, GetDeviceChain],
  EthernetOneDriverTypes USING [Encapsulation, ethernetOneBootLoaderHost],
  Protocol1 USING [GetContext],
  PupRouterDefs USING [NetworkContext],
  Stats USING [StatIncr];

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

  Device: PUBLIC <<Buffer>> TYPE = Driver.Device;
  breatherRunning, breatherStop: BOOLEAN ← FALSE;
  delay: CONDITION;
  bytesInBOLPacket: NATURAL = 512;

  -- 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;
    firstDevice: Device = Driver.GetDeviceChain[];
    bootLoader: POINTER ← DiskLessDefs.GetPointerToBootLoader[];
    FOR network: Device ← firstDevice, 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: Device ← firstDevice, 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, TRUE, bytesInBOLPacket];
        b.fo.driver.length ← bytesInBOLPacket;
        -- the boot loader has the encapsulation in it already
        Inline.LongCOPY[
          from: bootLoader, nwords: bytesInBOLPacket / 2,
	  to: @b.linkLayer.blockPointer];
        LOOPHOLE[
	  b.linkLayer.blockPointer,
	  LONG POINTER TO EthernetOneDriverTypes.Encapsulation]↑ ← [
	    ethernetOne[
	    ethernetOneDest: EthernetOneDriverTypes.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.