-- File: Breather.mesa,  Last Edit: HGM  February 10, 1981  5:28 PM

DIRECTORY
  Process USING [Detach, SetTimeout, MsecToTicks],
  CommUtilDefs USING [CopyLong],
  BootServerDefs USING [statLife],
  DiskLessDefs USING [GetPointerToBootLoader],
  StatsDefs USING [StatIncr],
  DriverDefs USING [Network, GetDeviceChain],
  BufferDefs USING [Buffer, GetFreeBuffer],
  DriverTypes USING [ethernetOneBootLoaderHost, ethernetEncapsulationOffset];

Breather: MONITOR
  IMPORTS
    Process, CommUtilDefs, BootServerDefs, DiskLessDefs, StatsDefs, DriverDefs,
    BufferDefs
  EXPORTS BootServerDefs
  SHARES BufferDefs =
  -- length and encapsulation
  BEGIN OPEN StatsDefs;


  dropDead: BOOLEAN ← FALSE;
  delay: CONDITION;

  -- This won't work with small buffers
  -- Send BreathOfLife RAW Packet every 5 seconds or so
  EthernetBreather: ENTRY PROCEDURE =
    BEGIN
    b: BufferDefs.Buffer;
    network, firstNetwork: DriverDefs.Network;
    bootLoader: POINTER ← DiskLessDefs.GetPointerToBootLoader[];
    firstNetwork ← DriverDefs.GetDeviceChain[];
    UNTIL dropDead DO
      WAIT delay;
      FOR network ← firstNetwork, network.next UNTIL network = NIL DO
	IF network.device # ethernetOne THEN LOOP;
	b ← BufferDefs.GetFreeBuffer[];
	b.length ← 256;
	-- the boot loader has the encapsulation in it already
	CommUtilDefs.CopyLong[
	  from: bootLoader, nwords: 256,
	  to: @b.encapsulation + DriverTypes.ethernetEncapsulationOffset];
	b.encapsulation ←
	  [ethernetOne[
	    etherSpare1:, etherSpare2:, etherSpare3:, etherSpare4:, etherSpare5:,
	    translationWorked: TRUE,
	    ethernetOneDest: DriverTypes.ethernetOneBootLoaderHost,
	    ethernetOneSource: network.hostNumber,
	    ethernetOneType: breathOfLife]];
	network.sendBuffer[b];
	StatIncr[BootServerDefs.statLife];
	ENDLOOP;
      ENDLOOP;
    dropDead ← FALSE;
    END;

  BreatherOn: PUBLIC PROCEDURE =
    BEGIN Process.Detach[FORK EthernetBreather[]]; END;

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


  -- initialization

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