-- File: SimpleNSIOPhoneImpl.mesa - last edit: -- AOF 9-Feb-88 10:15:28 -- HGM 31-Oct-83 21:33:58 -- WDK 9-Aug-83 17:05:33 -- Copyright (C) 1983, 1988 by Xerox Corporation. All rights reserved. << This module implements SimpleNSIO on the phone line. It supplies level one and level zero encapsulation. NOTE: The module SimpleNSIOEthernetOneImpl is a near-copy of this one. IF YOU MAKE A CHANGE HERE, it probably should be made to it too. SimplePUPIOEthernetOneImpl is another, somewhat less-similar module. >> DIRECTORY BootChannel USING [Result], Buffer USING [DeviceType], Checksum USING [ComputeChecksum], Device USING [Type], Environment USING [Byte, bytesPerWord, first64K], PhoneFace USING [ controlBlockSize, GetPacketLength, GetRecvStatus, GetSendStatus, Line, maxLines, phoneLine, QueueInput, QueueOutput, TurnOff, TurnOn], GermOps USING [GermWorldError], Inline USING [LowHalf], NSTypes USING [BufferBody, bytesPerIDPHeader, maxIDPWordsPerPacket, PacketType], PilotMP USING [cGermERROR], ProcessorFace USING [processorID], ResidentHeap USING [FreeNode, MakeNode], SimpleNSIO USING [ ByteCount, cantHandleDevice, Cleanups, timedOutBytes, timedOutResult], SpecialSystem USING [ HostNumber, NetworkNumber, nullNetworkNumber, ProcessorID, SocketNumber], System USING [ GetClockPulses, Microseconds, MicrosecondsToPulses, NetworkAddress, nullHostNumber, nullNetworkNumber, nullSocketNumber, Pulses, SocketNumber]; SimpleNSIOPhoneImpl: PROGRAM IMPORTS Checksum, PhoneFace, GermOps, Inline, ProcessorFace, ResidentHeap, System EXPORTS SimpleNSIO, System SHARES GermOps = BEGIN -- PARAMETERS: sendTimeOut: System.Microseconds = 3D6; bpw: NATURAL = Environment.bytesPerWord; -- TYPES AND VARIABLES: HostNumber: PUBLIC --System-- TYPE = SpecialSystem.HostNumber; NetworkNumber: PUBLIC --System-- TYPE = SpecialSystem.NetworkNumber; SocketNumber: PUBLIC --System-- TYPE = SpecialSystem.SocketNumber; NetworkAddress: TYPE = System.NetworkAddress; ByteCount: TYPE = SimpleNSIO.ByteCount; Byte: TYPE = Environment.Byte; PhonePacketType: TYPE = MACHINE DEPENDENT{ pupPhonePacket(100B), nsPhonePacket(300B), turnAroundPhonePacket(301B), turnAroundMTSPhonePacket(302B), terminatePhonePacket(303B), terminateAckPhonePacket(304B), (LAST[Byte])}; Encapsulation: TYPE = MACHINE DEPENDENT RECORD [ SELECT OVERLAID Buffer.DeviceType FROM phonenet => [ recognition: Byte, -- 0 for auto recognition of NS vs SDLC/HDLC pnType: PhonePacketType, pnSrcID: SpecialSystem.ProcessorID], ENDCASE]; phoneEncapsulationBytes: CARDINAL = bpw * SIZE[Encapsulation]; -- Level zero Ethernet packet format: LevelZeroPacket: TYPE = MACHINE DEPENDENT RECORD [ encapsulation(0): Encapsulation, levelOnePacket(4): NSTypes.BufferBody]; slop: CARDINAL = 12; -- Hal says we need this. We should ask why. bufferSize: CARDINAL = SIZE[Encapsulation] + NSTypes.maxIDPWordsPerPacket + slop; buffer: LONG POINTER TO LevelZeroPacket; line: PhoneFace.Line; longIocb: LONG POINTER ¬ NIL; returnData: RECORD [returnTo, returnedFrom: NetworkAddress]; --============================== -- Public Procedures --============================== GetRawBufferSize: PUBLIC PROCEDURE RETURNS [rawBufferSize: CARDINAL] = { RETURN[bufferSize]}; Initialize: PUBLIC PROC [ deviceType: Device.Type, deviceOrdinal: CARDINAL, rawBuffer: LONG POINTER, cleanups: SimpleNSIO.Cleanups] RETURNS [ result: BootChannel.Result, bufferBody: LONG POINTER TO NSTypes.BufferBody] = BEGIN IF deviceType # PhoneFace.phoneLine THEN RETURN[SimpleNSIO.cantHandleDevice, NIL]; IF line >= PhoneFace.maxLines THEN GermOps.GermWorldError[123]; IF line # 0 THEN GermOps.GermWorldError[124]; line ¬ deviceOrdinal; longIocb ¬ @Environment.first64K[ ResidentHeap.MakeNode[PhoneFace.controlBlockSize, a4].node]; buffer ¬ rawBuffer; bufferBody ¬ @buffer.levelOnePacket; TurnOn[]; RETURN[[ok[]], @buffer.levelOnePacket]; END; --Initialize-- Finalize: PUBLIC PROC [cleanups: SimpleNSIO.Cleanups] = BEGIN PhoneFace.TurnOff[]; [] ¬ ResidentHeap.FreeNode[Inline.LowHalf[longIocb]]; longIocb ¬ NIL; END; ReceivePacket: PUBLIC PROC [ getFrom: NetworkAddress, mySocket: System.SocketNumber, timeout: System.Microseconds] RETURNS [ result: BootChannel.Result, dataBytes: ByteCount, type: NSTypes.PacketType, source, destination: LONG POINTER TO NetworkAddress] = BEGIN startTime: System.Pulses = System.GetClockPulses[]; DO --UNTIL packet arrives on requested socket-- PhoneFace.QueueInput[line,longIocb, buffer, bufferSize*bpw]; UNTIL PhoneFace.GetRecvStatus[longIocb] # pending DO IF TimeExpired[timeout: timeout, startTime: startTime] THEN BEGIN PhoneFace.TurnOff[]; -- abort the input. TurnOn[]; RETURN[ dataBytes: SimpleNSIO.timedOutBytes, type: TRASH, source: TRASH, destination: TRASH, result: SimpleNSIO.timedOutResult]; END; ENDLOOP; IF PhoneFace.GetRecvStatus[longIocb] ~= ok THEN LOOP; IF buffer.encapsulation.pnType#nsPhonePacket THEN LOOP; IF ~TestChecksum[@buffer.levelOnePacket] THEN LOOP; IF buffer.levelOnePacket.destination.host ~= ProcessorFace.processorID THEN LOOP; IF getFrom.net ~= System.nullNetworkNumber AND getFrom.net ~= buffer.levelOnePacket.source.net THEN LOOP; IF getFrom.host ~= System.nullHostNumber AND getFrom.host ~= buffer.levelOnePacket.source.host THEN LOOP; IF getFrom.socket ~= System.nullSocketNumber AND getFrom.socket ~= buffer.levelOnePacket.source.socket THEN LOOP; IF mySocket ~= System.nullSocketNumber AND mySocket ~= buffer.levelOnePacket.destination.socket THEN LOOP; IF PhoneFace.GetPacketLength[longIocb] < BytesPerPhonePacket[ buffer.levelOnePacket.pktLength] THEN LOOP; IF buffer.levelOnePacket.pktLength >= NSTypes.bytesPerIDPHeader THEN EXIT; ENDLOOP; returnData.returnTo ¬ (source ¬ @buffer.levelOnePacket.source)­; returnData.returnedFrom ¬ (destination ¬ @buffer.levelOnePacket.destination)­; RETURN[ dataBytes: buffer.levelOnePacket.pktLength - NSTypes.bytesPerIDPHeader, type: buffer.levelOnePacket.packetType, source: @buffer.levelOnePacket.source, destination: @buffer.levelOnePacket.destination, result: [ok[]]]; END; --ReceivePacket-- ReturnPacket: PUBLIC PROC [dataBytes: ByteCount, type: NSTypes.PacketType] RETURNS [result: BootChannel.Result] = BEGIN buffer.levelOnePacket.source ¬ returnData.returnedFrom; buffer.levelOnePacket.destination ¬ returnData.returnTo; RETURN SendBuffer[dataBytes, type]; END; SendPacket: PUBLIC PROC [ dataBytes: ByteCount, type: NSTypes.PacketType, sourceSocket: SocketNumber, dest: NetworkAddress] RETURNS [result: BootChannel.Result] = BEGIN buffer.encapsulation ¬ [ phonenet[ recognition: 0, pnType: nsPhonePacket, pnSrcID: LOOPHOLE[ProcessorFace.processorID]]]; buffer.levelOnePacket.source ¬ [ net: SpecialSystem.nullNetworkNumber, host: ProcessorFace.processorID, socket: sourceSocket]; buffer.levelOnePacket.destination ¬ dest; [] ¬ SendBuffer[dataBytes, type]; -- %%%%%% STARTUP KROCK RETURN SendBuffer[dataBytes, type]; END; --============================== -- Private Procedures --============================== Error: PROC = {GermOps.GermWorldError[PilotMP.cGermERROR]}; SendBuffer: PROC [dataBytes: ByteCount, type: NSTypes.PacketType] RETURNS [result: BootChannel.Result] = -- Sends buffer; doesn't return till it is sent (but times out if can't send). BEGIN startTime: System.Pulses; buffer.encapsulation ¬ [ phonenet[ recognition: 0, pnType: nsPhonePacket, pnSrcID: LOOPHOLE[ProcessorFace.processorID]]]; buffer.levelOnePacket.pktLength ¬ dataBytes + NSTypes.bytesPerIDPHeader; buffer.levelOnePacket.transportControl ¬ [ trace: FALSE, filler: 0, hopCount: 0]; buffer.levelOnePacket.packetType ¬ type; SetChecksum[@buffer.levelOnePacket]; PhoneFace.QueueOutput[line, longIocb, buffer, BytesPerPhonePacket[buffer.levelOnePacket.pktLength]]; startTime ¬ System.GetClockPulses[]; DO --until sent or timed out IF PhoneFace.GetSendStatus[longIocb] # pending THEN EXIT; IF TimeExpired[timeout: sendTimeOut, startTime: startTime] THEN { PhoneFace.TurnOff[]; TurnOn[]; EXIT}; ENDLOOP; RETURN[[ok[]]]; END; --SendBuffer-- SetChecksum: PROC [b: LONG POINTER TO NSTypes.BufferBody] = { b.checksum ¬ Checksum.ComputeChecksum[ 0, (b.pktLength + 1 - 2)/2, @b.pktLength]}; TestChecksum: PROC [b: LONG POINTER TO NSTypes.BufferBody] RETURNS [BOOLEAN] = { RETURN[ b.checksum = Checksum.ComputeChecksum[ 0, (b.pktLength + 1 - 2)/2, @b.pktLength] OR b.checksum = 177777B]}; TimeExpired: PROC [timeout, startTime: System.Microseconds] RETURNS [BOOLEAN] = BEGIN IF timeout = LAST[System.Microseconds] THEN RETURN[FALSE] ELSE RETURN[ (System.GetClockPulses[] - startTime) > System.MicrosecondsToPulses[ timeout]]; END; TurnOn: PROC = {PhoneFace.TurnOn[0]}; BytesPerPhonePacket: PROC [bodyBytes: CARDINAL] RETURNS [bytes: CARDINAL] = BEGIN words: CARDINAL ¬ SIZE[Encapsulation] + (bodyBytes + bpw-1)/bpw; bytes ¬ words * bpw; END; END.