-- SetGMTUsingEthernet (September 1, 1982 4:16 pm by Taft) DIRECTORY EthernetFace USING [AddCleanup, ControlBlock, controlBlockSize, DeviceHandle, GetNextDevice, GetPacketLength, GetStatus, GlobalStatePtr, globalStateSize, nullDeviceHandle, QueueInput, QueueOutput, RemoveCleanup, TurnOff, TurnOn], Environment USING [Base, Long], Inline USING [BITOR], PilotMP USING [cClient, cTimeNotAvailable], OISCPConstants USING [timeServerSocket], System USING [gmtEpoch, LocalTimeParameters, WestEast], ProcessorFace USING [GreenwichMeanTime, ProcessorID, processorID, SetGreenwichMeanTime, SetMP], ResidentHeap USING [first64K, MakeNode], TemporarySetGMT USING [], Zone USING [Status]; SetGMTUsingEthernet: PROGRAM IMPORTS EthernetFace, Inline, ProcessorFace, ResidentHeap EXPORTS TemporarySetGMT SHARES ProcessorFace = BEGIN OPEN System; SetGMT: PUBLIC PROC RETURNS [ valid: BOOLEAN, params: LocalTimeParameters] = BEGIN valid ← FALSE; DO ProcessorFace.SetMP[PilotMP.cTimeNotAvailable]; IF EthernetExists[] THEN BEGIN time: ProcessorFace.GreenwichMeanTime; [time: time, ltp: params] ← GetTime[]; IF time#gmtEpoch THEN {ProcessorFace.SetGreenwichMeanTime[time]; valid ← TRUE; ProcessorFace.SetMP[PilotMP.cClient]; RETURN}; END; ENDLOOP; END; Byte: TYPE = [0..377B]; -- 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, timeLow: CARDINAL, direction: WestEast, -- depends on being same as in System zone: [0..127], zoneMinutes: [0..255], beginDST, endDST: CARDINAL, spare: ARRAY [5..8) OF WORD]; packetTypeOis: CARDINAL = 3000B; protocolTypeReqRep: CARDINAL = 123; timeRequest: CARDINAL = 1; timeReply: CARDINAL = 2; broadcast: ProcessorFace.ProcessorID = [177777B, 177777B, 177777B]; Address: TYPE = RECORD [ net: RECORD [a, b: WORD] ← [0,0], host: ProcessorFace.ProcessorID, socket: WORD ]; Encapsulation: TYPE = MACHINE DEPENDENT RECORD [ eDest, eSource: ProcessorFace.ProcessorID, packetType: CARDINAL ]; Header: TYPE = MACHINE DEPENDENT RECORD [ checksum, length: CARDINAL, transportControl, oisType: Byte, dest, source: Address, id1, id2: WORD, clientType: WORD ]; Request: TYPE = MACHINE DEPENDENT RECORD [ encap: Encapsulation, head: Header]; Reply: TYPE = MACHINE DEPENDENT RECORD [ encap: Encapsulation, head: Header, data: NetTime]; DriverNeedsSomeGlobalStorage: PUBLIC ERROR = CODE; ResidentHeapError: ERROR = CODE; GetTime: PROC RETURNS [ time: ProcessorFace.GreenwichMeanTime, ltp: LocalTimeParameters] = BEGIN OPEN EthernetFace; minWordsPerEthernetPacket: CARDINAL = (64/2)-2; --*** Should move to DriverTypes ether: DeviceHandle = GetNextDevice[nullDeviceHandle]; global: GlobalStatePtr; -- Allocate space when needed status: Zone.Status; iocbRelative: Environment.Base RELATIVE POINTER; iocb: ControlBlock; 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 globalStateSize # 0 THEN ERROR DriverNeedsSomeGlobalStorage; [iocbRelative, status] ← ResidentHeap.MakeNode[controlBlockSize, a4]; IF status#okay THEN ERROR ResidentHeapError; iocb ← LOOPHOLE[@ResidentHeap.first64K[iocbRelative]]; request↑ ← [ [ eDest: broadcast, eSource: ProcessorFace.processorID, packetType: packetTypeOis], [ checksum: 177777B, length: 2*SIZE[Header], transportControl: 0, oisType: protocolTypeReqRep, dest: [host: broadcast, socket: OISCPConstants.timeServerSocket], source: [host: ProcessorFace.processorID, socket: socket], id1: id1, id2: id2, clientType: 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 = OISCPConstants.timeServerSocket AND reply.head.id1 = id1 AND reply.head.id2 = id2 AND reply.head.clientType = timeReply THEN BEGIN nt: POINTER TO NetTime = @reply.data; LOOPHOLE[time, Environment.Long] ← [num[lowbits: nt.timeLow, highbits: nt.timeHigh]]; ltp ← [direction: nt.direction, zone: nt.zone, beginDST: nt.beginDST, zoneMinutes: nt.zoneMinutes, endDST: nt.endDST]; TurnOff[ether]; RemoveCleanup[ether]; RETURN END; -- 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]; time ← gmtEpoch; RETURN END; EthernetExists: PROCEDURE RETURNS [BOOLEAN] = BEGIN OPEN EthernetFace; RETURN[GetNextDevice[nullDeviceHandle] # nullDeviceHandle]; END; END. LOG Time: November 10, 1980 6:35 PM By: Forrest Action: Create from EthernetOne version of August 20, 1980 2:18 PM Time: November 13, 1980 6:47 PM By: HGM+RKJ Action: ? Time: November 14, 1980 5:25 PM By: Johnsson Action: ? Time: January 12, 1981 2:15 PM By: Forrest+RKJ Action: ? Time: January 22, 1981 12:40 PM By: Gobbel Action: Get iocb storage from resident heap instead of local frame; add LocalTimeParameters Time: February 4, 1981 6:04 PM By: McJones Action: SystemExtras => System; use OISCPConstants.TimeServerSocket Time: February 6, 1981 10:05 AM By: Luniewski Action: Typo: TimeServerSocket => timeServerSocket Time: February 25, 1981 4:30 PM By: BLyon Action: enforced minimun packet size on ethernet. Time: March 12, 1981 5:34 PM By: Yokota Action: Bug fix in SetGMT, MP is always set to 937 if time is not set properly. Time: March 19, 1981 2:06 PM By: Yokota Action: 990 instead of 930 is set at exit from SetGMT. September 1, 1982 4:14 pm Taft Get time from net even if already known locally, in order to obtain the local time parameters. (This makes it the same as SetGMTUsingEthernetOne. Why did they change it?)