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