-- 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....