-- 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?)