-- Copyright (C) 1983, 1984, 1985 by Xerox Corporation. All rights reserved.
-- SimplePhoneNetworkDriver.mesa, HGM, 10-Jun-85 22:17:10
-- SimplePhoneNetworkDriver.mesa, LSK, 9-Dec-84 18:36:28
-- Discarded Dialing and HalfDuplex, Copy Encapsulation from old DriverTypes
-- From PhoneNetworkDriver.mesa (last edited by: AOF on: 16-Feb-83 9:40:08)
DIRECTORY
Environment USING [Block, Byte],
Inline USING [LowHalf],
Process USING [Detach, InitializeCondition, SetPriority, MsecToTicks],
ProcessPriorities USING [priorityIOHigh],
System USING [
GetClockPulses, GetGreenwichMeanTime, HostNumber, localHostNumber, MicrosecondsToPulses,
nullHostNumber, nullNetworkNumber, Pulses, PulsesToMicroseconds],
Buffer USING [AccessHandle, Buffer, MakePool, NSBuffer, PupBuffer, Type],
CommFlags USING [driverStats],
CommUtil USING [GetEthernetHostNumber],
Driver USING [
NetworkObject, Network, PutOnGlobalDoneQueue,
AddDeviceToChain, GetInputBuffer, PutOnGlobalInputQueue, ReturnFreeBuffer],
DriverTypes USING [DeviceType, Encapsulation],
PhoneCreate USING [],
PhoneNetFriends USING [PhoneNetInfo, NetEnumerator, nullNetEnumerate],
PhoneNetExtras USING [
leaf, leafBytesSend, leafDupsFiltered, leafPktsSend,
nsBytesSend, nsCongestion, nsDupsFiltered, nsTooGreedy,
pupBytesSend, pupCongestion, pupDupsFiltered, pupTooGreedy],
PupTypes USING [PupErrorCode, PupHostID, PupSocketID],
RS232C USING [
ChannelHandle, CompletionHandle, ChannelSuspended, CommParamObject,
DeviceStatus, Get, GetStatus, PhysicalRecord, PhysicalRecordHandle, Put,
Restart, SetParameter, Suspend, TransmitNow, TransferStatus, TransferWait];
SimplePhoneNetworkDriver: MONITOR
IMPORTS Buffer, CommUtil, Driver, Inline, Process, RS232C, System
EXPORTS Buffer, PhoneCreate, PhoneNetFriends =
BEGIN
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 DriverTypes.DeviceType FROM
phonenet => [
framing0, framing1, framing2, framing3, framing4, framing5: Byte,
recognition: Byte, -- 0 for auto recognition of OISCP vs SDLC/HDLC
pnType: PhonePacketType,
pnSrcID: System.HostNumber],
ENDCASE];
phoneEncapsulationOffset: CARDINAL = 3;
phoneEncapsulationBytes: CARDINAL = 8;
encapsulationTrap: BOOLEAN [TRUE..TRUE] =
(SIZE[Encapsulation] = SIZE[DriverTypes.Encapsulation]);
-- EXPORTed TYPEs
Network: PUBLIC TYPE = Driver.Network;
InfoRecord: TYPE = RECORD [
channelHandle: RS232C.ChannelHandle,
packetToSend: CONDITION,
currentSendBuffer: Buffer.Buffer,
firstHiSendBuffer, lastHiSendBuffer: Buffer.Buffer,
firstLoSendBuffer, lastLoSendBuffer: Buffer.Buffer,
packetsOnSendQueue: CARDINAL,
timeSendStarted: System.Pulses,
timeLastRecv: System.Pulses,
bitsPerSecond: LONG CARDINAL,
pool: Buffer.AccessHandle,
network: Driver.NetworkObject, -- phone network object for Router
stats: PhoneNetFriends.PhoneNetInfo,
loophole: CrapForINRLoophole];
CrapForINRLoophole: TYPE = MONITORED RECORD [
clientData: LONG UNSPECIFIED,
lineNumber: CARDINAL];
maxHiPriWords: CARDINAL = (2 + 50 + 22)/2; -- 50 data bytes in a pup
maxQueueDepth: CARDINAL ← 15; -- For each of Pup, NS, ...
maxForwarderDepth: CARDINAL ← 10;
maxConnectionDepth: CARDINAL ← 5;
leafSocket: PupTypes.PupSocketID = PhoneNetExtras.leaf;
outstandingGets: CARDINAL = 2;
info: InfoRecord;
me: System.HostNumber ← System.localHostNumber;
CreateSimplePhoneNet: PUBLIC PROCEDURE [
lineNumber: CARDINAL, chHandle: RS232C.ChannelHandle, commParams: RS232C.CommParamObject] =
BEGIN
Process.InitializeCondition[@info.packetToSend, Process.MsecToTicks[1000]];
IF CommFlags.driverStats THEN info.stats ← [
state: data,
timeStarted: System.GetGreenwichMeanTime[],
timeConnectionEstablished: System.GetGreenwichMeanTime[],
remoteHostNumber: System.nullHostNumber,
protocolVersion: old,
lineNumber: NULL,
duplexity: full,
lineSpeed: bps9600,
speed: 0, -- Observed, Kilobits/second
negotiationMode: NULL,
ourEntityClass: NULL,
theirEntityClass: NULL,
halfDuplexMode: NULL,
hardwareStatsAvailable: TRUE,
clientData: 0,
clientHostNumber: NULL,
sendQueueLength: 0,
stats: ALL [0] ];
info.currentSendBuffer ← NIL;
info.currentSendBuffer ← NIL;
info.firstHiSendBuffer ← NIL;
info.lastHiSendBuffer ← NIL;
info.firstLoSendBuffer ← NIL;
info.lastLoSendBuffer ← NIL;
info.packetsOnSendQueue ← 0;
info.bitsPerSecond ← 0;
info.network ← [
next: NIL,
decapsulateBuffer: Decapsulate,
encapsulateAndSendPup: SendPup,
encapsulateAndSendNS: SendNS,
sendRawBuffer: SendRawBuffer,
encapsulateAndForwardPup: ForwardPup,
encapsulateAndForwardNS: ForwardNS,
activateDriver: ActivateDriver,
deactivateDriver: NIL,
deleteDriver: NIL,
changeNumberOfInputBuffers: NIL,
index:,
pupNetNumber: 0,
pupHostNumber: CommUtil.GetEthernetHostNumber[],
device: phonenet,
alive: TRUE,
buffers: 0,
netNumber: System.nullNetworkNumber,
pupStats: NIL,
statsLevel0: @info.loophole,
statsLevel1: NIL];
info.stats.lineNumber ← lineNumber;
info.stats.remoteHostNumber ← System.nullHostNumber;
info.channelHandle ← chHandle;
info.loophole.clientData ← @info.stats;
info.loophole.lineNumber ← lineNumber;
RS232C.SetParameter[info.channelHandle, [dataTerminalReady[TRUE]]];
RS232C.SetParameter[info.channelHandle, [requestToSend[TRUE]]];
info.pool ← Buffer.MakePool[1, outstandingGets];
Driver.AddDeviceToChain[@info.network];
Process.Detach[FORK Receiver[]];
Process.Detach[FORK Sender[]];
Process.Detach[FORK Watcher[]];
END;
-- 2400 baud is 300 bytes/sec. Allow 10% for slop and whatever to get 270.
pulsesPerByte: System.Pulses = [(System.MicrosecondsToPulses[1000000]/270)+1];
recvIdleTimeout: System.Pulses = System.MicrosecondsToPulses[30000000];
Watcher: ENTRY PROCEDURE =
BEGIN
watch: CONDITION;
tick: CONDITION;
Process.InitializeCondition[@watch, Process.MsecToTicks[1000]];
Process.InitializeCondition[@tick, 1];
DO
now: System.Pulses = System.GetClockPulses[];
b: Buffer.Buffer ← info.currentSendBuffer;
IF b # NIL AND (now - info.timeSendStarted) > pulsesPerByte*b.driver.length*2 THEN
BEGIN
info.stats.remoteHostNumber ← System.nullHostNumber;
RS232C.Suspend[info.channelHandle, output];
UNTIL info.packetsOnSendQueue = 0 DO WAIT tick; ENDLOOP;
RS232C.Restart[info.channelHandle, output];
info.stats.remoteHostNumber ← System.nullHostNumber;
END;
WAIT watch;
ENDLOOP;
END;
-- **************** Decapsulation ****************
Decapsulate: PROCEDURE [b: Buffer.Buffer] RETURNS [type: Buffer.Type] =
BEGIN
encapsulation: LONG POINTER TO Encapsulation = LOOPHOLE[@b.encapsulation];
bytes: CARDINAL ← 2*b.driver.length;
IF bytes < phoneEncapsulationBytes THEN GOTO Rejected;
bytes ← bytes - phoneEncapsulationBytes;
SELECT encapsulation.pnType FROM
nsPhonePacket =>
BEGIN
IF bytes < b.ns.pktLength THEN GOTO Rejected;
type ← ns;
END;
pupPhonePacket =>
BEGIN
IF bytes < b.pup.pupLength THEN GOTO Rejected;
type ← pup;
END;
ENDCASE => GOTO Rejected;
info.stats.remoteHostNumber ← encapsulation.pnSrcID;
EXITS Rejected =>
BEGIN
type ← rejected;
IF CommFlags.driverStats THEN StatIncr[@info.stats.stats[pktsRejected]];
END;
END;
-- **************** Packet Transport / Sending ****************
SendPup: ENTRY PROCEDURE [b: Buffer.PupBuffer, host: PupTypes.PupHostID] =
BEGIN
high: BOOLEAN;
friends, pups: CARDINAL ← 0;
encapsulation: LONG POINTER TO Encapsulation = LOOPHOLE[@b.encapsulation];
encapsulation↑ ← [
phonenet[
framing0: 0, framing1: 0, framing2: 0, framing3: 0, framing4: 0,
framing5: 0, recognition: 0,
pnType: pupPhonePacket, pnSrcID: me] ];
b.driver.length ← (b.pup.pupLength + 1 + phoneEncapsulationBytes)/2;
[friends, pups, ] ← CountFriends[b, info.firstLoSendBuffer, friends, pups];
high ← b.driver.length < maxHiPriWords AND (friends = 0);
[friends, pups, ] ← CountFriends[b, info.firstHiSendBuffer, friends, pups];
IF friends > maxConnectionDepth THEN
BEGIN
Driver.PutOnGlobalDoneQueue[b];
StatIncr[@info.stats.stats[connTooGreedy]];
StatIncr[@info.stats.stats[PhoneNetExtras.pupTooGreedy]];
RETURN;
END;
IF pups > maxQueueDepth THEN
BEGIN
Driver.PutOnGlobalDoneQueue[b];
StatIncr[@info.stats.stats[congestion]];
StatIncr[@info.stats.stats[PhoneNetExtras.pupCongestion]];
RETURN;
END;
QueueOutputBuffer[b, high];
StatIncr[@info.stats.stats[pupSent]];
StatBump[@info.stats.stats[PhoneNetExtras.pupBytesSend], b.driver.length*2];
IF b.pup.source.socket = leafSocket OR b.pup.dest.socket = leafSocket THEN {
StatIncr[@info.stats.stats[PhoneNetExtras.leafPktsSend]];
StatBump[@info.stats.stats[PhoneNetExtras.leafBytesSend], b.driver.length*2]; };
END;
SendNS: ENTRY PROCEDURE [b: Buffer.NSBuffer, host: System.HostNumber] =
BEGIN
high: BOOLEAN;
friends, ns: CARDINAL ← 0;
encapsulation: LONG POINTER TO Encapsulation = LOOPHOLE[@b.encapsulation];
encapsulation↑ ← [
phonenet[
framing0: 0, framing1: 0, framing2: 0, framing3: 0, framing4: 0,
framing5: 0, recognition: 0,
pnType: nsPhonePacket, pnSrcID: me] ];
b.driver.length ← (b.ns.pktLength + 1 + phoneEncapsulationBytes)/2;
[friends, ns, ] ← CountFriends[b, info.firstLoSendBuffer, friends, ns];
high ← b.driver.length < maxHiPriWords AND (friends = 0);
[friends, ns, ] ← CountFriends[b, info.firstHiSendBuffer, friends, ns];
IF friends > maxConnectionDepth THEN
BEGIN
Driver.PutOnGlobalDoneQueue[b];
StatIncr[@info.stats.stats[connTooGreedy]];
StatIncr[@info.stats.stats[PhoneNetExtras.nsTooGreedy]];
RETURN;
END;
IF ns > maxQueueDepth THEN
BEGIN
Driver.PutOnGlobalDoneQueue[b];
StatIncr[@info.stats.stats[congestion]];
StatIncr[@info.stats.stats[PhoneNetExtras.nsCongestion]];
RETURN;
END;
QueueOutputBuffer[b, high];
StatIncr[@info.stats.stats[nsSent]];
StatBump[@info.stats.stats[PhoneNetExtras.nsBytesSend], b.driver.length*2];
END;
SendRawBuffer: ENTRY PROCEDURE [b: Buffer.Buffer] =
BEGIN
IF info.packetsOnSendQueue > maxQueueDepth THEN
BEGIN
Driver.PutOnGlobalDoneQueue[b];
StatIncr[@info.stats.stats[congestion]];
RETURN;
END;
QueueOutputBuffer[b, FALSE];
StatIncr[@info.stats.stats[rawSent]];
END;
ForwardPup: ENTRY PROCEDURE [b: Buffer.PupBuffer, host: PupTypes.PupHostID]
RETURNS [PupTypes.PupErrorCode] =
BEGIN
high: BOOLEAN;
dup, lic, ate: BOOLEAN;
friends, pups: CARDINAL ← 0;
encapsulation: LONG POINTER TO Encapsulation = LOOPHOLE[@b.encapsulation];
encapsulation↑ ← [
phonenet[
framing0: 0, framing1: 0, framing2: 0, framing3: 0, framing4: 0,
framing5: 0, recognition: 0,
pnType: pupPhonePacket, pnSrcID: me] ];
b.driver.length ← (b.pup.pupLength + 1 + phoneEncapsulationBytes)/2;
[friends, pups, dup] ← CountFriends[b, info.firstLoSendBuffer, friends, pups];
high ← b.driver.length < maxHiPriWords AND (friends = 0);
[friends, pups, lic] ← CountFriends[b, info.firstHiSendBuffer, friends, pups];
[friends, pups, ate] ← CountFriends[b, info.currentSendBuffer, friends, pups];
IF ((b.pup.pupType = aData OR b.pup.pupType = data) AND (dup OR lic OR ate) OR
(b.pup.pupType = aData AND friends # 0 AND b.pup.pupLength = 22)) THEN {
-- Barf, what an ugly hack to put into a gateway
-- Duplicate data/aData OR (empty aData (probe) when something on the queue)
StatIncr[@info.stats.stats[PhoneNetExtras.pupDupsFiltered]];
RETURN[LOOPHOLE[10002]]; };
IF (b.pup.source.socket = leafSocket OR b.pup.dest.socket = leafSocket)
AND (dup OR lic OR ate) THEN {
StatIncr[@info.stats.stats[PhoneNetExtras.leafDupsFiltered]];
RETURN[LOOPHOLE[10002]]; };
IF friends > maxConnectionDepth THEN
BEGIN
StatIncr[@info.stats.stats[connTooGreedy]];
StatIncr[@info.stats.stats[PhoneNetExtras.pupTooGreedy]];
RETURN[gatewayResourceLimitsPupErrorCode];
END;
IF pups > maxForwarderDepth THEN
BEGIN
StatIncr[@info.stats.stats[congestion]];
StatIncr[@info.stats.stats[PhoneNetExtras.pupCongestion]];
RETURN[gatewayResourceLimitsPupErrorCode];
END;
QueueOutputBuffer[b, high];
StatIncr[@info.stats.stats[pupSent]];
StatBump[@info.stats.stats[PhoneNetExtras.pupBytesSend], b.driver.length*2];
IF b.pup.source.socket = leafSocket OR b.pup.dest.socket = leafSocket THEN {
StatIncr[@info.stats.stats[PhoneNetExtras.leafPktsSend]];
StatBump[@info.stats.stats[PhoneNetExtras.leafBytesSend], b.driver.length*2]; };
RETURN[noErrorPupErrorCode];
END;
ForwardNS: ENTRY PROCEDURE [b: Buffer.PupBuffer, host: System.HostNumber] =
BEGIN
high: BOOLEAN;
dup, lic, ate: BOOLEAN;
friends, ns: CARDINAL ← 0;
encapsulation: LONG POINTER TO Encapsulation = LOOPHOLE[@b.encapsulation];
encapsulation↑ ← [
phonenet[
framing0: 0, framing1: 0, framing2: 0, framing3: 0, framing4: 0,
framing5: 0, recognition: 0,
pnType: nsPhonePacket, pnSrcID: me] ];
b.driver.length ←
(b.ns.pktLength + 1 + phoneEncapsulationBytes)/2;
[friends, ns, dup] ← CountFriends[b, info.firstLoSendBuffer, friends, ns];
high ← b.driver.length < maxHiPriWords AND (friends = 0);
[friends, ns, lic] ← CountFriends[b, info.firstHiSendBuffer, friends, ns];
[friends, ns, ate] ← CountFriends[b, info.currentSendBuffer, friends, ns];
IF dup OR lic OR ate THEN
BEGIN
Driver.PutOnGlobalDoneQueue[b];
StatIncr[@info.stats.stats[PhoneNetExtras.nsDupsFiltered]];
RETURN;
END;
IF friends > maxConnectionDepth THEN
BEGIN
Driver.PutOnGlobalDoneQueue[b];
StatIncr[@info.stats.stats[connTooGreedy]];
StatIncr[@info.stats.stats[PhoneNetExtras.nsTooGreedy]];
RETURN;
END;
IF ns > maxForwarderDepth THEN
BEGIN
Driver.PutOnGlobalDoneQueue[b];
StatIncr[@info.stats.stats[congestion]];
StatIncr[@info.stats.stats[PhoneNetExtras.nsCongestion]];
RETURN;
END;
QueueOutputBuffer[b, high];
StatIncr[@info.stats.stats[nsSent]];
StatBump[@info.stats.stats[PhoneNetExtras.nsBytesSend], b.driver.length*2];
END;
CountFriends: INTERNAL PROCEDURE [
b: Buffer.Buffer, head: Buffer.Buffer, friends, neighbors: CARDINAL]
RETURNS [newFriends, newNeighbors: CARDINAL, headerMatch: BOOLEAN] =
BEGIN
encapsulation: LONG POINTER TO Encapsulation = LOOPHOLE[@b.encapsulation];
headerMatch ← FALSE;
SELECT encapsulation.pnType FROM
pupPhonePacket => {
FOR maybe: Buffer.PupBuffer ← head, maybe.next UNTIL maybe = NIL DO
encap: LONG POINTER TO Encapsulation = LOOPHOLE[@maybe.encapsulation];
IF encap.pnType = pupPhonePacket THEN {
neighbors ← neighbors + 1;
IF b.pup.dest = maybe.pup.dest THEN {
PupHeader: TYPE = ARRAY [0..11) OF WORD;
x: LONG POINTER TO PupHeader ← LOOPHOLE[@b.pup.pupLength];
y: LONG POINTER TO PupHeader ← LOOPHOLE[@maybe.pup.pupLength];
IF x↑ = y↑ THEN headerMatch ← TRUE;
friends ← friends + 1; }; };
ENDLOOP; };
nsPhonePacket => {
FOR maybe: Buffer.PupBuffer ← head, maybe.next UNTIL maybe = NIL DO
encap: LONG POINTER TO Encapsulation = LOOPHOLE[@maybe.encapsulation];
IF encap.pnType = nsPhonePacket THEN {
neighbors ← neighbors + 1;
IF b.ns.destination = maybe.ns.destination THEN {
SELECT b.ns.packetType FROM
sequencedPacket => {
IF b.ns.sequenceNumber = maybe.ns.sequenceNumber THEN headerMatch ← TRUE; };
packetExchange => {
IF b.ns.exchangeID = maybe.ns.exchangeID THEN headerMatch ← TRUE; };
ENDCASE => NULL;
friends ← friends + 1; }; };
ENDLOOP; };
ENDCASE => NULL; -- You get what you deserve
RETURN[friends, neighbors, headerMatch]
END;
QueueOutputBuffer: INTERNAL PROCEDURE [b: Buffer.Buffer, high: BOOLEAN] =
BEGIN
b.network ← LONG[@info.network];
info.packetsOnSendQueue ← info.packetsOnSendQueue + 1;
b.next ← NIL;
IF high THEN
BEGIN
IF info.firstHiSendBuffer = NIL THEN info.firstHiSendBuffer ← b
ELSE info.lastHiSendBuffer.next ← b;
info.lastHiSendBuffer ← b;
END
ELSE
BEGIN
IF info.firstLoSendBuffer = NIL THEN info.firstLoSendBuffer ← b
ELSE info.lastLoSendBuffer.next ← b;
info.lastLoSendBuffer ← b;
END;
NOTIFY info.packetToSend;
END;
Sender: PROCEDURE =
BEGIN
Process.SetPriority[ProcessPriorities.priorityIOHigh];
DO
StartSending[];
SendIt[];
FinishSending[];
ENDLOOP;
END;
StartSending: ENTRY PROCEDURE =
BEGIN
b: Buffer.Buffer;
UNTIL (info.packetsOnSendQueue # 0) DO WAIT info.packetToSend; ENDLOOP;
SELECT TRUE FROM
info.firstHiSendBuffer # NIL =>
BEGIN
b ← info.firstHiSendBuffer;
info.firstHiSendBuffer ← b.next;
END;
info.firstLoSendBuffer # NIL =>
BEGIN
b ← info.firstLoSendBuffer;
info.firstLoSendBuffer ← b.next;
END;
ENDCASE => RETURN;
info.currentSendBuffer ← b;
END;
SendIt: PROCEDURE =
BEGIN
complHandle: RS232C.CompletionHandle;
rec: RS232C.PhysicalRecord ← [header: [NIL, 0, 0], body:, trailer: [NIL, 0, 0]];
xferstatus: RS232C.TransferStatus;
b: Buffer.Buffer ← info.currentSendBuffer;
rec.body.blockPointer ← LOOPHOLE[@b.encapsulation + phoneEncapsulationOffset];
rec.body.startIndex ← 0;
rec.body.stopIndexPlusOne ← b.driver.length*2; -- even bytes
complHandle ← RS232C.Put[info.channelHandle, @rec !
RS232C.ChannelSuspended => GOTO Zapped];
info.timeSendStarted ← System.GetClockPulses[];
[, xferstatus] ← RS232C.TransmitNow[info.channelHandle, complHandle];
IF xferstatus = aborted THEN GOTO Zapped;
BEGIN
bits: CARDINAL ← 7 + 16*b.driver.length + 16 + 7;
now: System.Pulses ← System.GetClockPulses[];
micro: LONG CARDINAL ← System.PulsesToMicroseconds[[now-info.timeSendStarted]];
-- ARHG!!! 4000 * 1000000 overflows a LONG CARDINAL
bitsPerSecond: LONG CARDINAL ← ((100000*bits)/micro)*10;
info.bitsPerSecond ← (63*info.bitsPerSecond + bitsPerSecond)/64;
info.stats.speed ← Inline.LowHalf[info.bitsPerSecond/1000];
END;
IF CommFlags.driverStats THEN
IF xferstatus = success THEN
BEGIN
StatIncr[@info.stats.stats[pktsSent]];
StatBump[@info.stats.stats[bytesSent], b.driver.length*2];
END
ELSE StatIncr[@info.stats.stats[sendErrorBadStatus]];
EXITS Zapped => StatIncr[@info.stats.stats[queueTooOld]];
END;
FinishSending: ENTRY PROCEDURE =
BEGIN
Driver.PutOnGlobalDoneQueue[info.currentSendBuffer];
info.packetsOnSendQueue ← info.packetsOnSendQueue - 1;
info.currentSendBuffer ← NIL;
END;
-- **************** Packet Transport / Receiving ****************
Receiver: PROCEDURE =
BEGIN
recArray: ARRAY [0..outstandingGets) OF RS232C.PhysicalRecord ←
ALL[[[NIL, 0, 0], [NIL, 0, 0], [NIL, 0, 0]]];
bufferArray: ARRAY [0..outstandingGets) OF Buffer.Buffer ← ALL[NIL];
complArray: ARRAY [0..outstandingGets) OF RS232C.CompletionHandle;
bufCount: CARDINAL ← 0;
nextBuf: Buffer.Buffer;
Process.SetPriority[ProcessPriorities.priorityIOHigh];
info.timeLastRecv ← System.GetClockPulses[];
DO
FOR i: CARDINAL IN [0..outstandingGets) DO
nextBuf ← Driver.GetInputBuffer[];
IF bufferArray[i] # NIL THEN
BEGIN
okToDispose: BOOLEAN ← TRUE;
IF nextBuf=NIL THEN
BEGIN
IF bufCount <= 1 THEN
BEGIN
okToDispose ← FALSE;
nextBuf ← bufferArray[i]; -- we keep this buffer because we can't get another
END
ELSE
BEGIN
bufCount ← bufCount - 1;
END;
END;
AwaitAndDisposeOfFrame[complArray[i], bufferArray[i], okToDispose];
END -- non-NIL bufferArray[i]
ELSE
BEGIN
IF nextBuf # NIL THEN bufCount ← bufCount + 1;
END;
bufferArray[i] ← nextBuf;
IF bufferArray[i] # NIL THEN
BEGIN
recHandle: RS232C.PhysicalRecordHandle ← @recArray[i];
b: Buffer.Buffer ← bufferArray[i];
recHandle.body ← [
LOOPHOLE[@b.encapsulation + phoneEncapsulationOffset],
0, (b.driver.length - phoneEncapsulationOffset)*2];
complArray[i] ← RS232C.Get[info.channelHandle, recHandle];
END;
ENDLOOP;
ENDLOOP; -- of UNTIL
END;
AwaitAndDisposeOfFrame: PROCEDURE [
complHandle: RS232C.CompletionHandle, b: Buffer.Buffer, okToDispose: BOOLEAN] =
BEGIN
transferStatus: RS232C.TransferStatus;
globalStatus: RS232C.DeviceStatus;
bytes: CARDINAL;
checksum: CARDINAL = 2;
[bytes, transferStatus] ← RS232C.TransferWait[info.channelHandle, complHandle];
IF transferStatus = success THEN
BEGIN
encapsulation: LONG POINTER TO Encapsulation = LOOPHOLE[@b.encapsulation];
info.timeLastRecv ← System.GetClockPulses[];
IF ~okToDispose THEN RETURN;
b.driver.length ← (bytes - checksum)/2;
b.network ← LONG[@info.network];
b.driver.faceStatus ← unknown[101H];
b.time ← System.GetClockPulses[]; --record time received
Driver.PutOnGlobalInputQueue[b];
IF CommFlags.driverStats THEN
BEGIN
StatIncr[@info.stats.stats[pktsReceived]];
StatBump[@info.stats.stats[bytesReceived], bytes - checksum];
END;
END
ELSE
BEGIN -- bad frame => free the buffer
IF ~okToDispose THEN RETURN;
Driver.ReturnFreeBuffer[b];
IF CommFlags.driverStats AND (transferStatus # aborted) THEN
BEGIN
statsPtr: POINTER TO LONG CARDINAL;
statsPtr ←
SELECT transferStatus FROM
dataLost => @info.stats.stats[rcvErrorDataLost],
checksumError => @info.stats.stats[rcvErrorCRC],
frameTimeout => @info.stats.stats[rcvErrorFrameTimeout],
deviceError => @info.stats.stats[rcvDeviceError],
ENDCASE => @info.stats.stats[rcvErrorUnknown];
StatIncr[statsPtr];
END;
IF transferStatus = deviceError THEN
BEGIN
globalStatus ← RS232C.GetStatus[info.channelHandle];
IF globalStatus.dataLost THEN -- clear the info lost latch bit
BEGIN
RS232C.SetParameter[info.channelHandle, [latchBitClear[globalStatus]]];
IF CommFlags.driverStats THEN StatIncr[@info.stats.stats[rcvErrorNoGet]];
END;
END;
END;
END;
-- **************** Driver Management (by Router) ****************
ActivateDriver: PROCEDURE =
BEGIN
END;
-- **************** Statistics ****************
StatIncr: PROCEDURE [counter: POINTER TO LONG CARDINAL] = INLINE
BEGIN
counter↑ ← (counter↑ + 1);
END;
StatBump: PROCEDURE [
counter: POINTER TO LONG CARDINAL, bumpAmount: CARDINAL] = INLINE
BEGIN
counter↑ ← (counter↑ + bumpAmount);
END;
-- **************** Keep Kluger/INR happy ****************
GetDriverInfo: PUBLIC PROCEDURE [lineNumber: CARDINAL]
RETURNS [--found:-- BOOLEAN, --info:-- PhoneNetFriends.PhoneNetInfo] =
BEGIN
IF info.network.alive AND lineNumber = info.stats.lineNumber THEN
RETURN [TRUE, info.stats];
RETURN[FALSE, ];
END;
StatsPtrToInfo: PUBLIC PROCEDURE [statsLevel0: LONG POINTER]
RETURNS [clientData: LONG UNSPECIFIED, lineNumber: CARDINAL] =
-- statsLevel0 argument is from a phonenet network object
BEGIN
stats: LONG POINTER TO CrapForINRLoophole = LOOPHOLE[statsLevel0];
RETURN [stats.clientData, stats.lineNumber];
END;
EnumerateDriverInfo: PUBLIC PROCEDURE [current: PhoneNetFriends.NetEnumerator]
RETURNS [PhoneNetFriends.NetEnumerator, PhoneNetFriends.PhoneNetInfo] =
BEGIN
nonNullNetEnumerate: PhoneNetFriends.NetEnumerator = LONG[LOOPHOLE [1]];
IF (current = PhoneNetFriends.nullNetEnumerate) AND info.network.alive THEN
RETURN [nonNullNetEnumerate, info.stats] ELSE
RETURN [PhoneNetFriends.nullNetEnumerate, info.stats]; -- no more
END;
-- init
info.network.alive ← FALSE;
END....