-- Copyright (C) 1984 by Xerox Corporation. All rights reserved. -- SetGMTUsingEthernet.mesa, HGM, 8-Jan-84 1:01:18 DIRECTORY EthernetFace USING [ AddCleanup, ControlBlock, controlBlockSize, DeviceHandle, GetNextDevice, GetPacketLength, GetStatus, GlobalStatePtr, globalStateSize, nullDeviceHandle, QueueInput, QueueOutput, RemoveCleanup, TurnOff, TurnOn], Environment USING [Base, Byte, bytesPerWord, Long], HostNumbers USING [broadcastHostNumber, HostNumber], Inline USING [BITOR], NSConstants USING [timeServerSocket], PilotMP USING [cTimeNotAvailable], ProcessorFace USING [ GetGreenwichMeanTime, GreenwichMeanTime, gmtEpoch, ProcessorID, processorID, SetGreenwichMeanTime, SetMP, mp], ResidentHeap USING [first64K, MakeNode], TemporarySetGMT USING [TimeZoneDirection], Zone USING [Status]; SetGMTUsingEthernet: PROGRAM IMPORTS EthernetFace, Inline, ProcessorFace, ResidentHeap EXPORTS TemporarySetGMT SHARES ProcessorFace = BEGIN OPEN ProcessorFace; SetGMT: PUBLIC PROC [ earliestAcceptableTime, latestAcceptableTime: ProcessorFace.GreenwichMeanTime] RETURNS [ paramsValid: BOOLEAN, zoneDirection: TemporarySetGMT.TimeZoneDirection, zone: [0..12], zoneMinutes: [0..59], beginDST: [0..366], endDST: [0..366]] = BEGIN teMP: CARDINAL = ProcessorFace.mp; ProcessorFace.SetMP[PilotMP.cTimeNotAvailable]; DO networkTimeFound: BOOLEAN; gmt: ProcessorFace.GreenwichMeanTime; [networkTimeFound, gmt, zoneDirection, zone, zoneMinutes, beginDST, endDST] ← GetNetworkGMT[]; IF networkTimeFound THEN { ProcessorFace.SetGreenwichMeanTime[gmt]; ProcessorFace.SetMP[teMP]; RETURN[TRUE, zoneDirection, zone, zoneMinutes, beginDST, endDST]}; IF ((gmt ← ProcessorFace.GetGreenwichMeanTime[]) # ProcessorFace.gmtEpoch) AND ((PFSecondsSinceEpoch[gmt] > PFSecondsSinceEpoch[ earliestAcceptableTime]) OR (earliestAcceptableTime = ProcessorFace.gmtEpoch)) AND ((PFSecondsSinceEpoch[gmt] <= PFSecondsSinceEpoch[latestAcceptableTime]) OR (latestAcceptableTime = ProcessorFace.gmtEpoch)) THEN { SetMP[teMP]; RETURN[FALSE, , , , , ]}; ENDLOOP; END; -- D'Lions run off the wall frequency, so their clock needs no fixing up once set FixupClock: PUBLIC PROCEDURE = {}; Byte: TYPE = Environment.Byte; -- Following started as a copy of GTime.mesa -- as edited by Johnsson on July 12, 1979 8:31 AM NetTime: TYPE = MACHINE DEPENDENT RECORD [ -- this is what comes in a TimeReply Packet timeHigh(0), timeLow(1): CARDINAL, direction(2): TemporarySetGMT.TimeZoneDirection, zone(3): [0..127], zoneMinutes(4): [0..255], beginDST(5), endDST(6): CARDINAL, errorAccurate(7): BOOLEAN, errorLow(8), errorHigh(9): CARDINAL]; packetTypeOis: CARDINAL = 3000B; protocolTypeReqRep: CARDINAL = 4; -- NSTypes.PacketType[packetExchange] packetExchangeClient: CARDINAL = 1; timeRequest: CARDINAL = 1; timeReply: CARDINAL = 2; tsProtocolVersion: CARDINAL = 2; Address: TYPE = MACHINE DEPENDENT RECORD [ net: RECORD [a, b: WORD] ← [0, 0], host: HostNumbers.HostNumber, socket: WORD]; Encapsulation: TYPE = MACHINE DEPENDENT RECORD [ eDest, eSource: HostNumbers.HostNumber, packetType: CARDINAL]; Header: TYPE = MACHINE DEPENDENT RECORD [ checksum, length: CARDINAL, transportControl, oisType: Byte, dest, source: Address, id1, id2: WORD, clientType: WORD, tsVersion, tsPacketType: WORD]; Request: TYPE = MACHINE DEPENDENT RECORD [encap: Encapsulation, head: Header]; Reply: TYPE = MACHINE DEPENDENT RECORD [ encap: Encapsulation, head: Header, data: NetTime]; iocb: EthernetFace.ControlBlock; DriverNeedsSomeGlobalStorage: PUBLIC ERROR = CODE; ResidentHeapError: ERROR = CODE; GetNetworkGMT: PUBLIC PROC RETURNS [ networkTimeFound: BOOLEAN, timeFromNetwork: ProcessorFace.GreenwichMeanTime, zoneDirection: TemporarySetGMT.TimeZoneDirection, zone: [0..12], zoneMinutes: [0..59], beginDST: [0..366], endDST: [0..366]] = BEGIN OPEN EthernetFace; minWordsPerEthernetPacket: CARDINAL = (64/2) - 2; --*** Should move to DriverTypes ether: DeviceHandle = GetNextDevice[nullDeviceHandle]; global: GlobalStatePtr; -- Allocate space when needed inputSize: CARDINAL = MAX[SIZE[Reply], 32] + slop; slop: CARDINAL = 12; in: ARRAY [0..inputSize + 3) OF CARDINAL; out: ARRAY [0..SIZE[Request] + 3) OF CARDINAL; request: POINTER TO Request = Inline.BITOR[@out, 3]; reply: POINTER TO Reply = Inline.BITOR[@in, 3]; id1: WORD = 1234B; id2: WORD = 56710B; socket: WORD = 111213B; IF ~EthernetExists[] THEN RETURN[FALSE, ProcessorFace.gmtEpoch, , , , , ]; IF globalStateSize # 0 THEN ERROR DriverNeedsSomeGlobalStorage; request↑ ← [ [ eDest: HostNumbers.broadcastHostNumber, eSource: ProcessorFace.processorID, packetType: packetTypeOis], [ checksum: 177777B, length: Environment.bytesPerWord*SIZE[Header], transportControl: 0, oisType: protocolTypeReqRep, dest: [ host: HostNumbers.broadcastHostNumber, socket: LOOPHOLE[NSConstants.timeServerSocket]], source: [host: ProcessorFace.processorID, socket: socket], id1: id1, id2: id2, clientType: packetExchangeClient, tsVersion: tsProtocolVersion, tsPacketType: timeRequest]]; AddCleanup[ether]; THROUGH [0..3) DO THROUGH [0..3) DO TurnOff[ether]; TurnOn[ether, LOOPHOLE[ProcessorFace.processorID], 0, 0, global]; reply.encap.packetType ← 0; QueueOutput[ ether, request, MAX[SIZE[Request], minWordsPerEthernetPacket], iocb]; THROUGH [0..LAST[CARDINAL]/2) DO IF GetStatus[iocb] # pending THEN BEGIN IF GetStatus[iocb] = ok AND GetPacketLength[iocb] >= SIZE[Reply] AND reply.encap.packetType = packetTypeOis AND reply.head.dest.host = ProcessorFace.processorID AND reply.head.dest.socket = socket AND reply.head.source.socket = LOOPHOLE[NSConstants.timeServerSocket, WORD] AND reply.head.id1 = id1 AND reply.head.id2 = id2 AND reply.head.clientType = packetExchangeClient AND reply.head.tsVersion = tsProtocolVersion AND reply.head.tsPacketType = timeReply THEN { nt: POINTER TO NetTime = @reply.data; LOOPHOLE[timeFromNetwork, Environment.Long] ← [ num[lowbits: nt.timeLow, highbits: nt.timeHigh]]; TurnOff[ether]; RemoveCleanup[ether]; RETURN[ TRUE, timeFromNetwork, nt.direction, nt.zone, nt.zoneMinutes, nt.beginDST, nt.endDST]}; -- Start (another) read either because the send just -- finshed or we didn't like the -- packet that just arrived. QueueInput[ether, reply, inputSize, iocb]; END; ENDLOOP; ENDLOOP; ENDLOOP; TurnOff[ether]; RemoveCleanup[ether]; timeFromNetwork ← ProcessorFace.gmtEpoch; RETURN[FALSE, timeFromNetwork, , , , , ] END; PFSecondsSinceEpoch: PROCEDURE [gmt: ProcessorFace.GreenwichMeanTime] RETURNS [LONG CARDINAL] = INLINE {RETURN[gmt - ProcessorFace.gmtEpoch]}; EthernetExists: PROCEDURE RETURNS [BOOLEAN] = BEGIN OPEN EthernetFace; RETURN[GetNextDevice[nullDeviceHandle] # nullDeviceHandle]; END; -- Initialization BEGIN iocbRelative: Environment.Base RELATIVE POINTER; status: Zone.Status; [iocbRelative, status] ← ResidentHeap.MakeNode[ EthernetFace.controlBlockSize, a4]; IF status # okay THEN ERROR ResidentHeapError; iocb ← LOOPHOLE[@ResidentHeap.first64K[iocbRelative]]; END; END....