PSCommandCImpl.mesa
Copyright (C) Xerox Corporation 1983, 1984, 1985. All rights reserved.
Last edited by Jacks 21-Nov-85 11:24:18
Ruseli Binsol: October 15, 1986 2:21:07 pm PDT
<<Exports miscellaneous procedures to PSCommand, PSCommandInternal and PrintServiceAccounting. Included are procs for getting status and procs that watch the status of various print engines. The proc RegisterAccountProc (exported by PrintServiceAccounting) is used by clients to register a proc that will be called every time a document completes to pass certain information to be used for statistical accounting.>>
DIRECTORY
BansheeStatus USING [Type],
BansheeTest USING [WaitRepairModeRequest],
ControlMessages USING [Key],
D1Status USING [Type],
D1Test USING [WaitRepairModeRequest],
DecomposerControl USING [ModifyTraceLevel, NotifyProc, Status, Stopped],
ForwardingControl USING [ModifyTraceLevel, Status],
FaxStatus USING [Type],
FX3500Status USING [Type],
FX3500Test USING [WaitRepairModeRequest],
Heap USING [FreeNode, MakeNode],
MarkerControl USING [EngineSpecific, MarkerStatus],
MergeControl USING [ModifyTraceLevel, NotifyProc, Status],
MiscUtilities USING [KeyForBansheeStatus, KeyForD1Status, KeyForFaxStatus, KeyForFX3500Status, KeyForRavenStatus],
NSName USING [NameRecord, nullNameRecord],
NSString USING [CopyString, FreeString, String],
PrintQueue USING [Empty, Next, nilQueueObjectHandle],
PrintServiceAccounting USING [AccountProc],
Process USING [Detach, Pause, SecondsToTicks],
PSAsyncMsg USING [Insert, InsertArray, Msg, nullInsertArray, Proc, PutMesaString],
PSCommand USING [DocumentProc, Error, ListDocuments, StartRepairMode, StopPrinting, TraceParameters],
PSCommandExtras,
PSCommandInternal USING [commandHeap, currentCondition, DisableQueuing, EnableQueuing, markerProcs, state, stateSpace],
PSKMessages USING [GetHandle],
PSState USING [CurrentActivity, ServiceState, State, StateHandle, TraceLevel],
PSVolume USING [PagesAllocated],
QueueControl USING [CompletionProc, ModifyTraceLevel],
RavenStatus USING [Type],
RavenTest USING [WaitRepairModeRequest],
Space USING [ForceOut],
SpoolControl USING [ModifyTraceLevel, SpoolStatus, Status],
System USING [nullID, nullNetworkAddress, UniversalID],
TargetPS USING [Error, GetPrinterProperties, GetPrinterStatus],
TargetPSStatus USING [Communication, Current, Properties],
Time USING [Current],
XMessage USING [Get, Handle, MsgKey],
XString USING [ReaderBody];
PSCommandCImpl: CEDAR MONITOR
IMPORTS BansheeTest, D1Test, DecomposerControl, ForwardingControl, FX3500Test, Heap, MergeControl, MiscUtilities, NSString, PrintQueue, Process, PSCommand, PSCommandInternal, PSKMessages, PSVolume, QueueControl, RavenTest, Space, SpoolControl, TargetPS, Time, XMessage
EXPORTS PrintServiceAccounting, PSCommand, PSCommandExtras, PSCommandInternal
SHARES XString = BEGIN
OPEN PSCommandInternal;
accountProc: PrintServiceAccounting.AccountProc ← NIL; --client-provided accounting procedure set by RegisterAccountProc
Declarations for handling asynchonous message procs registered with PSCommand via RegisterAsyncMessageProc.
AsyncMsgProcArray: TYPE = LONG DESCRIPTOR FOR ARRAY OF PSAsyncMsg.Proc ← DESCRIPTOR[NIL, 0];
procArrayLengthIncrement: CARDINAL = 5;
procCount: CARDINAL ← 0;
asyncMsgProcArray: AsyncMsgProcArray ← DESCRIPTOR[Heap.MakeNode[
commandHeap, SIZE[PSAsyncMsg.Proc] * procArrayLengthIncrement], procArrayLengthIncrement];
lastSpaceRecoveryDocID, beforeLastSpaceRecoveryDocID: System.UniversalID ← System.nullID; --Set to the value of the particular document's id if the document runs out of disk space while in progress (decomposing or merging). The first variable holds the ID of the last document to run out of disk space and the second variable holds the ID of the document before last to run out of disk space. Documents are allowed to run out of space twice before we give up trying to recover disk space and abort it.
Message domain handle:
controlMsgs: XMessage.Handle ← PSKMessages.GetHandle[control];
========================================================
PUBLIC PROCEDURES EXPORTED BY PSCOMMAND:
========================================================
ResetStatistics: PUBLIC PROCEDURE = BEGIN --exported by PSCommand
state.statisticsReset ← Time.Current[];
state.docsPrinted.grandTotal ← state.docsAborted.grandTotal ←
state.testPatternsPrinted.grandTotal ← state.docsRetried.grandTotal ←
state.docsPurged.grandTotal ← state.commErrors.grandTotal ← 0;
state.docsPrinted.total ← state.docsAborted.total ←
state.testPatternsPrinted.total ← state.docsRetried.total ←
state.docsPurged.total ← state.commErrors.total ← 0;
WITH s: state SELECT FROM
fax495 => BEGIN
s.docsTransmitted.grandTotal ← s.docsTransmitted.total ← 0;
END;
ENDCASE;
Space.ForceOut[stateSpace];
END; --ResetStatistics
SetTrace: PUBLIC PROCEDURE [traceParms: PSCommand.TraceParameters] =
BEGIN
--exported by PSCommand
sT, dT, mT: PSState.TraceLevel;
sT ← SELECT traceParms.spooler FROM none => none, mini => mini, ENDCASE => verbose;
IF sT # state.spoolerTrace THEN BEGIN
state.spoolerTrace ← sT;
SpoolControl.ModifyTraceLevel[LOOPHOLE[state.spoolerTrace]];
END;
dT ← SELECT traceParms.decomposer FROM none => none, mini => mini, ENDCASE => verbose;
IF dT # state.formatterTrace THEN BEGIN
state.formatterTrace ← dT;
DecomposerControl.ModifyTraceLevel[LOOPHOLE[state.formatterTrace]];
IF state.option = feps9700 THEN
MergeControl.ModifyTraceLevel[LOOPHOLE[state.formatterTrace]];
END;
mT ← SELECT traceParms.marker FROM none => none, mini => mini, ENDCASE => verbose;
IF mT # state.markerTrace THEN BEGIN
state.markerTrace ← mT;
QueueControl.ModifyTraceLevel[LOOPHOLE[state.markerTrace]];
SELECT state.option FROM
feps9700 => ForwardingControl.ModifyTraceLevel[LOOPHOLE[state.markerTrace]];
ENDCASE => markerProcs.modifyTraceLevel[LOOPHOLE[state.markerTrace]];
END;
Space.ForceOut[stateSpace];
END; --SetTrace
***** Client procedures for obtaining status information *****:
ServiceState: PUBLIC PROCEDURE RETURNS [PSState.ServiceState] =
BEGIN --exported by PSCommandExtras
RETURN [currentCondition];
END;
GetPrintServiceStatus: PUBLIC PROCEDURE RETURNS [PSState.StateHandle] =
BEGIN --exported by PSCommand
IF currentCondition # notInitialized THEN
Fill in correct paper size(s) for engines that give internal indication of size(s) loaded...
WITH s: state SELECT FROM
bansheeDl => BEGIN
dStatus: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: dStatus SELECT FROM
bansheeDl => s.paper ← d.paper;
ENDCASE => ERROR;
Space.ForceOut[stateSpace];
END;
d1 => BEGIN
dStatus: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: dStatus SELECT FROM
d1 => BEGIN
s.paperSize ← d.paperSize;
s.trayEmpty ← d.trayEmpty;
END;
ENDCASE => ERROR;
Space.ForceOut[stateSpace];
END;
fx3500 => BEGIN
dStatus: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: dStatus SELECT FROM
fx3500 => BEGIN
s.paperSupply ← d.paperSupply;
s.topPaperTrayEmpty ← d.topTrayEmpty;
s.bottomPaperTrayEmpty ← d.bottomTrayEmpty;
END;
ENDCASE => ERROR;
Space.ForceOut[stateSpace];
END;
ENDCASE;
RETURN[state];
END; --GetPrintServiceStatus
GetPrintServiceActivity: PUBLIC PROCEDURE RETURNS [PSState.CurrentActivity] =
BEGIN --exported by PSCommand
IF currentCondition = notInitialized THEN
Don't call any modules to get status before they've been initialized!
RETURN[[
condition: notInitialized,
spooler: disabled,
decomposer: disabled,
queuePages: 0,
fontPages: 0,
option: unknown[]]]
ELSE BEGIN
spoolStatus: SpoolControl.SpoolStatus ← SpoolControl.Status[];
queuePages: LONG CARDINAL ← PSVolume.PagesAllocated[spooled];
fontPages: LONG CARDINAL ← PSVolume.PagesAllocated[font];
activity: PSState.CurrentActivity ← [condition: currentCondition,
spooler: SELECT TRUE FROM
PrintQueue.Empty[queueStage: inactive] => full,
NOT spoolStatus.enabled => disabled,
spoolStatus.currentConnections >= spoolStatus.connectionsAllowed => busy,
spoolStatus.currentConnections > 0 => spooling,
ENDCASE => available,
decomposer: SELECT TRUE FROM
NOT state.clientControl.formatterEnabled OR
NOT state.internalControl.formatterEnabled => disabled,
DecomposerControl.Status[].decomposing => busy
ENDCASE => available,
queuePages: queuePages,
fontPages: fontPages, --set below
option: unknown[] --Compiler won't accept select stmt (below) here. **AJ 12/20/83
];
IF state.option = feps9700 THEN BEGIN
forwarding: BOOLEANFALSE;
forwardingStatus: TargetPSStatus.Communication ← okay;
[forwarding, forwardingStatus] ← ForwardingControl.Status[];
activity.option ←
feps9700[
merger: SELECT TRUE FROM
NOT state.clientControl.formatterEnabled OR
NOT state.internalControl.formatterEnabled => disabled,
MergeControl.Status[].merging => busy,
ENDCASE => available,
forwarder: SELECT TRUE FROM
NOT state.clientControl.markerEnabled OR
NOT state.internalControl.markerEnabled => disabled,
forwarding => busy,
ENDCASE => available,
forwardingStatus: forwardingStatus
]
END
ELSE BEGIN
The status returned by the marker doesn't not correctly
indicate when the marker is disabled; that information
has to come from the state record.
markerStatus: MarkerControl.MarkerStatus ← markerProcs.status[];
markerDisabled: BOOLEANNOT state.clientControl.markerEnabled
OR NOT state.internalControl.markerEnabled;
WITH m: markerStatus.engine SELECT FROM
bansheeDl => activity.option ← bansheeDl[marker: IF markerDisabled THEN disabled
ELSE markerStatus.activity, bansheeStatus: LOOPHOLE[m.banshee]];
d1 => activity.option ← d1[marker: IF markerDisabled THEN disabled
ELSE markerStatus.activity, d1Status: LOOPHOLE[m.d1]];
fax295 => activity.option ← fax295[marker: IF markerDisabled THEN disabled
ELSE markerStatus.activity, faxStatus: LOOPHOLE[m.fax]];
fax495 => activity.option ← fax495[marker: IF markerDisabled THEN disabled
ELSE markerStatus.activity, faxStatus: LOOPHOLE[m.fax]];
fx3500 => activity.option ← fx3500[marker: IF markerDisabled THEN disabled
ELSE markerStatus.activity, fx3500Status: LOOPHOLE[m.fx3500]];
raven => activity.option ← raven[marker: IF markerDisabled THEN disabled
ELSE markerStatus.activity, ravenStatus: LOOPHOLE[m.raven]];
ENDCASE => ERROR;
END;
RETURN[activity];
END;
END; --GetPrintServiceActivity
GetTargetPSStatus: PUBLIC PROCEDURE RETURNS [
activity: TargetPSStatus.Current, properties: TargetPSStatus.Properties] = BEGIN
WITH s: state SELECT FROM
feps9700 =>
IF s.targetPSAddress = System.nullNetworkAddress THEN
ERROR PSCommand.Error[[targetPSNotSet[]]]
ELSE BEGIN
activity ← TargetPS.GetPrinterStatus[target: s.targetPSAddress
! TargetPS.Error => ERROR PSCommand.Error[[targetPS[why]]]
];
properties ← TargetPS.GetPrinterProperties[target: s.targetPSAddress
! TargetPS.Error => ERROR PSCommand.Error[[targetPS[why]]]
END;
Store current values in state record:
s.paperSupply ← activity.paperSupply;
s.twoSidedCopy ← properties.twoSided;
s.stapling ← properties.staple;
Space.ForceOut[stateSpace];
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
END; --GetTargetPSStatus
==================================================================
PUBLIC PROCEDURE EXPORTED BY PRINTSERVICEACCOUNTING:
==================================================================
RegisterAccountProc: PUBLIC ENTRY PROCEDURE [new: PrintServiceAccounting.AccountProc]
RETURNS [old: PrintServiceAccounting.AccountProc] = BEGIN --exported by PrintServiceAccounting
Client calls this procedure to register an accounting procedure. The accounting procedure is called every time a document completes by DocumentCompleted to pass various data that may be usedfor accouting purposes. This proc is monitored so that the accounting proc cannot be changed (or made nil) just when it is being called.
accountProc is a global variable
old ← accountProc;
accountProc ← new;
END; --RegisterAccountProc
===============================================================
PUBLIC PROCEDURES EXPORTED BY PSCOMMANDINTERNAL:
===============================================================
***** Procedures for handling asynchronous messages *****:
PutAsyncMsgFromKey: PUBLIC PROCEDURE [msg: PSAsyncMsg.Msg, insertArray: PSAsyncMsg.InsertArray ← PSAsyncMsg.nullInsertArray] = BEGIN
Exported by PSCommandInternal.
Passed to all control modules; called to notify clients of asynchronous messages.
FOR i: CARDINAL IN [0..procCount) DO
IF asyncMsgProcArray[i] # NIL THEN
asyncMsgProcArray[i][msg, insertArray];
ENDLOOP;
END; --PutAsyncMsgFromKey
RegisterAsyncMessageProc: PUBLIC PROCEDURE [asyncMsgProc: PSAsyncMsg.Proc] =
Stores proc passed by client into asynchronous message procedure array.
BEGIN --exported by PSCommand
GrowAsyncMsgProcArray: PROCEDURE [larger: CARDINAL] = BEGIN
oldAsyncMsgProcArray: AsyncMsgProcArray ← asyncMsgProcArray;
oldLength: CARDINAL = LENGTH[oldAsyncMsgProcArray];
newLength: CARDINAL = oldLength + larger;
asyncMsgProcArray ← DESCRIPTOR[Heap.MakeNode[
commandHeap, SIZE[PSAsyncMsg.Proc] * newLength], newLength];
FOR i: CARDINAL IN [0..oldLength) DO
asyncMsgProcArray[i] ← oldAsyncMsgProcArray[i];
ENDLOOP;
FOR i: CARDINAL IN [oldLength..newLength) DO
asyncMsgProcArray[i] ← NIL;
ENDLOOP;
Heap.FreeNode[commandHeap, BASE[oldAsyncMsgProcArray]];
END; --GrowAsyncMsgProcArray
IF procCount = 0 THEN
FOR i: CARDINAL IN [0..LENGTH[asyncMsgProcArray]) DO
asyncMsgProcArray[i] ← NIL;
ENDLOOP;
IF procCount >= LENGTH[asyncMsgProcArray] THEN GrowAsyncMsgProcArray[procArrayLengthIncrement];
asyncMsgProcArray[procCount] ← asyncMsgProc;
procCount ← procCount + 1;
END; --RegisterAsyncMessageProc
***** Callback procs used when initializing various subsystems *****:
These procs are parameters for init procs of various subsystems (e.g. marker, decomposer, merger, etc.). They are called by the subsystem at certain times to provide notification of certain events and/or pass certain statistical information.
== Procedure parameters for MarkerInit.Init:
ReadyToMark: PUBLIC PROCEDURE = BEGIN --exported by PSCommandInternal
IF NOT state.spoolWhileMarking AND
state.internalControl.spooler = enabled THEN BEGIN
IF state.markerTrace = verbose THEN
PSAsyncMsg.PutMesaString["%%Disable Queuing"L];
PSCommandInternal.DisableQueuing[disabledForMarking];
END;
END; --ReadyToMark
FinishedMarking: PUBLIC SAFE PROCEDURE = BEGIN --exported by PSCommandInternal
IF state.internalControl.spooler = disabledForMarking THEN BEGIN
IF state.markerTrace = verbose THEN
PSAsyncMsg.PutMesaString["%%Enable Queuing"L];
PSCommandInternal.EnableQueuing[];
END;
END; --FinishedMarking
MarkingEngineFailure: PUBLIC SAFE PROCEDURE = BEGIN --exported by PSCommandInternal
systemName: NSName.NameRecord ← NSName.nullNameRecord;
systemName.local ← M[mSystemControl];
PutAsyncMsgFromKey[[domain: controlMsgs, key: XKey[mPrintEngineFailure]]];
PSCommand.StopPrinting[ --Printing stopped at client level.
user: @systemName, reason: M[mEngineFailure]];
END; --MarkingEngineFailure
== Procedure parameter for MergeControl.Init:
ProblemDuringMerge: PUBLIC MergeControl.NotifyProc =
PROCEDURE [queueObject: PrintQueue.QueueObjectHandle, code: NotifyProc, continuable: BOOLEAN] RETURNS [keepGoing: BOOLEAN]
BEGIN --exported by PSCommandInternal
WaitForMoreSpace: PROCEDURE = BEGIN
We try to recover space twice for a given document. If it still needs more space we set keepGoing to FALSE so it will be aborted. This proc checks the merged and forwarding queues to see if there are currently documents in progress. If so, it waits for them to complete and sets keepGoing to TRUE. If not, it sets keepGoing to FALSE.
keepGoing ← FALSE;
Make sure the current document that has run out of space is not the same as the document that ran out of space two times ago...
IF queueObject.uid # beforeLastSpaceRecoveryDocID THEN BEGIN
beforeLastSpaceRecoveryDocID ← lastSpaceRecoveryDocID;
lastSpaceRecoveryDocID ← queueObject.uid;
See if there are any documents already merged and, if so, wait until the merged queue is empty...
IF PrintQueue.Next[fromQueue: merged] # PrintQueue.nilQueueObjectHandle THEN BEGIN
PSAsyncMsg.PutMesaString["!!Waiting for merged docs to complete to get more disk space."L];
UNTIL PrintQueue.Empty[queueStage: merged] DO
Process.Pause[Process.SecondsToTicks[10]];
ENDLOOP;
keepGoing ← TRUE;
END;
See if there is a document currently forwarding and, if so, wait until the forwarding queue is empty...
IF PrintQueue.Next[fromQueue: forwarding] # PrintQueue.nilQueueObjectHandle THEN BEGIN
PSAsyncMsg.PutMesaString["!!Waiting for forwarding doc to complete to get more disk space."L];
UNTIL PrintQueue.Empty[queueStage: forwarding] DO
Process.Pause[Process.SecondsToTicks[10]];
ENDLOOP;
keepGoing ← TRUE;
END;
END;
IF NOT keepGoing THEN BEGIN
fileName: NSString.String ← NSString.CopyString[
z: commandHeap, s: queueObject.fileName]; --will be free by forked notify proc
Fork the following notification procedure to avoid monitor lock in MergeControlImpl...
Process.Detach[FORK NotifyClientThatThereAreNoResources[fileName]];
END;
END; --WaitForMoreSpace
SELECT code FROM
noResources => IF continuable THEN WaitForMoreSpace[]
ELSE BEGIN
fileName: NSString.String ← NSString.CopyString[
z: commandHeap, s: queueObject.fileName]; --will be free by forked notify proc
Fork the following notification procedure to avoid monitor lock in MergeControlImpl...
Process.Detach[FORK NotifyClientThatThereAreNoResources[fileName]];
keepGoing ← FALSE;
END;
ENDCASE => BEGIN
fileName: NSString.String ← NSString.CopyString[
z: commandHeap, s: queueObject.fileName]; --will be free by forked notify proc
Fork the following notification procedure to avoid monitor lock in MergeControlImpl...
Process.Detach[FORK NotifyClientOfUnrecoverableProblem[fileName]];
keepGoing ← FALSE;
END;
END; --ProblemDuringMerge
== Procedure parameter for DecomposerControl.Init:
ProblemDuringDecomposition: PUBLIC DecomposerControl.NotifyProc =
PROCEDURE [queueObject: PrintQueue.QueueObjectHandle,
code: NotifyProc, continuable: BOOLEAN]
RETURNS [keepGoing: BOOLEAN]
BEGIN --exported by PSCommandInternal
WaitForMoreSpace: PROCEDURE = BEGIN --NOTE: Insert code...
SELECT code FROM
pageTooComplicated => keepGoing ← continuable;
noResources => BEGIN
Display message only when keepGoing is FALSE.
fileName: NSString.String ← NSString.CopyString[
z: commandHeap, s: queueObject.fileName]; --will be free by forked notify proc
Fork the following notification procedure to avoid monitor lock in DecomposerControlImpl...
Process.Detach[FORK NotifyClientThatThereAreNoResources[fileName]];
keepGoing ← FALSE;
END;
ENDCASE;
END; --WaitForMoreSpace
NoDefaultFont: PROCEDURE = BEGIN
NotifyClientThatThereIsNoDefaultFont: SAFE PROCEDURE = BEGIN
systemName: NSName.NameRecord ← NSName.nullNameRecord;
systemName.local ← M[mSystemControl];
When the problem is no fonts, DecomposerControlImpl stops itself...
[] ← DecomposerControl.Stopped[wait];
PSCommand.StopPrinting[ --Printing stopped at client level.
user: @systemName, reason: M[mMissingDefaultFont]];
PutAsyncMsgFromKey[[domain: controlMsgs, key: XKey[mUINoDefaultFont]]];
END;
Fork the following notification procedure to avoid monitor lock in DecomposerControlImpl...
Process.Detach[FORK NotifyClientThatThereIsNoDefaultFont[]];
keepGoing ← FALSE;
END; --NoDefaultFont
SELECT code FROM
noResources, pageTooComplicated => WaitForMoreSpace[];
noDefaultFont => NoDefaultFont[];
ENDCASE => BEGIN
fileName: NSString.String ← NSString.CopyString[
z: commandHeap, s: queueObject.fileName]; --will be free by forked notify proc
Fork the following notification procedure to avoid monitor lock in DecomposerControlImpl...
Process.Detach[FORK NotifyClientOfUnrecoverableProblem[fileName]];
keepGoing ← FALSE;
END;
END; --ProblemDuringDecomposition
== Procedure parameter for QueueControl.Init:
DocumentCompleted: PUBLIC ENTRY QueueControl.CompletionProc =
[status, documentID, docsPrinted, docsTransmitted]--
This procedure is called every time a document completes, for the purpose of maintaining certain service statistics. Some of the statistics are saved in the PS state record and others are saved by the registered accounting proc. This proc is monitored so that the accounting proc cannot be changed (or made nil) just as it is being called.
BEGIN --exported by PSCommandInternal
CallAccountProc: PSCommand.DocumentProc =
[document] RETURNS [continue]--
BEGIN
accountProc[document];
continue ← FALSE;
END; --CallAccountProc
SELECT status FROM
spoolFailure => state.commErrors.total ← state.commErrors.total + 1;
aborted => state.docsAborted.total ← state.docsAborted.total + 1;
ENDCASE;
state.docsPrinted.total ← state.docsPrinted.total + docsPrinted;
WITH s: state SELECT FROM
fax495 =>
s.docsTransmitted.total ← s.docsTransmitted.total + docsTransmitted;
ENDCASE;
state.lastActivity ← Time.Current[];
Space.ForceOut[stateSpace];
If an accounting procedure has been registered, get the attributes
of the document just completed and pass them along.
IF accountProc # NIL THEN
PSCommand.ListDocuments[proc: CallAccountProc, filter: [id: documentID]];
END; --DocumentCompleted
***** Print engine status and repair mode watching procs *****:
BansheeStatusWatcher: PUBLIC PROCEDURE = BEGIN --exported by PSCommandInternal
preStatus, status: BansheeStatus.Type;
banshee: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH b: banshee SELECT FROM
bansheeDl => preStatus ← status ← LOOPHOLE[b.banshee];
ENDCASE => ERROR;
DO -- forever
banshee ← markerProcs.waitStatusChange[].engine;
WITH b: banshee SELECT FROM
bansheeDl => status ← LOOPHOLE[b.banshee];
ENDCASE => ERROR;
SELECT TRUE FROM
status = preStatus => NULL;
status = paperCassetteRemoved AND preStatus = noPaper => NULL;
status = clamshellOpen AND
preStatus IN [preRegistrationJam..paperCassetteRemoved] => NULL;
ENDCASE => BEGIN
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert;
insertArray[0].m ← MiscUtilities.KeyForBansheeStatus[status];
PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mPrinterStatus2]],
insertArray: DESCRIPTOR[insertArray]];
END;
preStatus ← status;
ENDLOOP;
END; -- BansheeStatusWatcher
D1StatusWatcher: PUBLIC PROCEDURE = BEGIN --exported by PSCommandInternal
preStatus, status: D1Status.Type;
d1: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: d1 SELECT FROM
d1 => preStatus ← status ← LOOPHOLE[d.d1];
ENDCASE => ERROR;
NOTE: Come back to this later and check the select stmt stuff.
DO -- forever
d1 ← markerProcs.waitStatusChange[].engine;
WITH d: d1 SELECT FROM
d1 => status ← LOOPHOLE[d.d1];
ENDCASE => ERROR;
SELECT TRUE FROM
state.mode.current = repair => NULL; -- no status while in Repair
status = preStatus => NULL;
status = trayUnlatched AND
preStatus IN [noA4Paper..noPaper] => NULL;
status = interlockOpen AND
(preStatus IN [notDelivered..tonerLow] OR
preStatus IN [fuserUnderTemperature..noPaper]) => NULL;
ENDCASE => BEGIN
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert;
insertArray[0].m ← MiscUtilities.KeyForD1Status[status];
PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mPrinterStatus2]],
insertArray: DESCRIPTOR[insertArray]];
END;
preStatus ← status;
ENDLOOP;
END; -- D1StatusWatcher
FaxStatusWatcher: PUBLIC PROCEDURE = BEGIN --exported by PSCommandInternal
preStatus, status: FaxStatus.Type;
fax: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH f: fax SELECT FROM
fax495 => preStatus ← status ← LOOPHOLE[f.fax];
ENDCASE => ERROR;
DO --forever
fax ← markerProcs.waitStatusChange[].engine;
WITH f: fax SELECT FROM
fax495 => status ← LOOPHOLE[f.fax];
ENDCASE => ERROR;
IF status # preStatus THEN BEGIN
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert;
insertArray[0].m ← MiscUtilities.KeyForFaxStatus[status];
PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mPrinterStatus2]],
insertArray: DESCRIPTOR[insertArray]];
END;
preStatus ← status;
ENDLOOP;
END; --FaxStatusWatcher
FX3500StatusWatcher: PUBLIC PROCEDURE = BEGIN --exported by PSCommandInternal
preStatus, status: FX3500Status.Type;
fx: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH f: fx SELECT FROM
fx3500 => preStatus ← status ← LOOPHOLE[f.fx3500];
ENDCASE => ERROR;
DO -- forever
fx ← markerProcs.waitStatusChange[].engine;
WITH f: fx SELECT FROM
fx3500 => status ← LOOPHOLE[f.fx3500];
ENDCASE => ERROR;
SELECT TRUE FROM
state.mode.current = repair => NULL; -- no status while in Repair
status = preStatus => NULL;
status = drawerOpen AND
(preStatus IN [feederJam..cheatError] OR
preStatus IN [fuserUnderTemperature..noPaper]) => NULL;
ENDCASE => BEGIN
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert;
insertArray[0].m ← MiscUtilities.KeyForFX3500Status[status];
PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mPrinterStatus2]],
insertArray: DESCRIPTOR[insertArray]];
END;
preStatus ← status;
ENDLOOP;
END; -- FX3500StatusWatcher
RavenStatusWatcher: PUBLIC PROCEDURE = BEGIN --exported by PSCommandInternal
preStatus, status: RavenStatus.Type;
raven: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH r: raven SELECT FROM
raven => preStatus ← status ← LOOPHOLE[r.raven];
ENDCASE => ERROR;
DO -- forever
raven ← markerProcs.waitStatusChange[].engine;
WITH r: raven SELECT FROM
raven => status ← LOOPHOLE[r.raven];
ENDCASE => ERROR;
SELECT TRUE FROM
state.mode.current = repair => NULL; -- no status while in Repair
status = preStatus => NULL;
status = traysUnlatched
AND preStatus IN [preRegistrationFault..fuserUnderTemperature] => NULL;
status = doorOpen
AND preStatus IN [preRegistrationFault..fuserUnderTemperature] => NULL;
ENDCASE => BEGIN
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert;
insertArray[0].m ← MiscUtilities.KeyForRavenStatus[status];
PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mPrinterStatus2]],
insertArray: DESCRIPTOR[insertArray]];
END;
preStatus ← status;
ENDLOOP;
END; -- RavenStatusWatcher
RepairModeWatcher: PUBLIC PROCEDURE = BEGIN --exported by PSCommandInternal
EnterRepair: PROC = BEGIN
PutAsyncMsgFromKey[[domain: controlMsgs, key: XKey[mRepairModeEntered]]];
PSCommand.StartRepairMode[];
PutAsyncMsgFromKey[[domain: controlMsgs, key: XKey[mRepairModeExited]]];
END; -- EnterRepair
IF state.mode.current = repair THEN EnterRepair[];
DO -- forever
SELECT state.option FROM
bansheeDl => BansheeTest.WaitRepairModeRequest[];
d1 => D1Test.WaitRepairModeRequest[];
fx3500 => FX3500Test.WaitRepairModeRequest[];
raven => RavenTest.WaitRepairModeRequest[];
ENDCASE => ERROR;
EnterRepair[];
ENDLOOP;
END; -- RepairModeWatcher
=================================
SUPPORT PROCS:
=================================
NotifyClientOfUnrecoverableProblem: PROCEDURE [documentName: NSString.String] =
BEGIN --IMPORTANT: Must free documentName allocated from commandHeap.
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert;
insertArray[0].s ← documentName;
PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mCantRecover]],
insertArray: DESCRIPTOR[insertArray]];
PutAsyncMsgFromKey[[domain: controlMsgs, key: XKey[mDocAborted]]];
NSString.FreeString[z: commandHeap, s: documentName];
END; --NotifyClientOfUnrecoverableProblem
NotifyClientThatThereAreNoResources: PROCEDURE [documentName: NSString.String] =
BEGIN --IMPORTANT: Must free documentName allocated from commandHeap.
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert;
insertArray[0].s ← documentName;
PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mInsufficientFreePages]],
insertArray: DESCRIPTOR[insertArray]];
PutAsyncMsgFromKey[[domain: controlMsgs, key: XKey[mDocAborted]]];
NSString.FreeString[z: commandHeap, s: documentName];
END; --NotifyClientThatThereAreNoResources
Proc for getting NSString from XMessage key
M: PROCEDURE [key: ControlMessages.Key] RETURNS [string: NSString.String] = BEGIN
r: XString.ReaderBody ← XMessage.Get[controlMsgs, ORD[key]];
string ← [bytes: LOOPHOLE[r.bytes], length: r.limit, maxlength: r.limit]
END;
XKey: PROCEDURE [key: ControlMessages.Key] RETURNS [xKey: XMessage.MsgKey] =
{RETURN[ORD[key]]};
END. --PSCommandDImpl
LOG (When-Who-What)
26-Mar-84 7:55:29 - Jacks - Created. (Split off from PSCommandCImpl)
4-Apr-84 9:28:52 - Jacks - Added support for multiple execs by redefining and renaming ExpungePrintService; ExpungePS is exported to PSCommandExtra temporarily for 8.0 release.
18-Apr-84 9:51:44 - Jacks - Now reset nBoots when stats are reset.
27-Apr-84 10:10:09 - Jacks - No longer reset nBoots when stats are reset!; check for nsExecStatus = notInitialized in GetPrintServiceStatus.
22-Jun-84 9:08:48 - Jacks - Added Register and UnRegister procs.
28-Jun-84 16:34:26 - Jacks - Fixed bug where serviceName got set to NIL in Register.
9-Jul-84 14:30:33 - Jacks - In Register and UnRegister "authProblem" now treated as non-fatal; added printServiceName and GetPrintServiceName.
9-Jul-84 18:24:34 - Jacks - Moved all current expunge proc functionality to client (PSTTYExecAImpl).
15-Sep-84 13:21:57 - Jacks - Updated to new 9.0 PS interfaces; added code for bansheeDl, fax295 and feps9700.
21-Sep-84 13:20:58 - Jacks - Moved Register and UnRegister to PSTTYExecAImpl; now allow GetPrintServiceStatus to be called before PS is initialized.
27-Sep-84 17:11:33 - Jacks - Renamed PSCommandCImpl from PSCommandDImpl.
19-Oct-84 10:27:31 - Jacks - Moved KeyFor*Status procs to new MiscUtilitiesImpl module; added GetTargetPSStatus; added feps9700 status calls to GetPSActivity.
2-Nov-84 10:20:38 - Jacks - Replace NSPrint call with TargetPS in GetTargetPSStatus.
16-Nov-84 12:37:53 - Jacks - GetTargetPSStatus became GetTargetPSActivity; added check for disabled marker to GetCurrentActivity.
28-Nov-84 16:27:13 - Jacks - Added RegisterAccountProc and callback procs.
12-Dec-84 14:36:28 - Jacks - Replaced GetTargetPSActivity with GetTargetPSStatus.
16-Jan-85 15:51:39 - Jacks - Added "ps" prefix to all new msg keys for 9.0.
15-Feb-85 14:57:16 - Jacks - Added banshee choice to RepairModeWatcher.
18-Jun-85 15:27:48 - Jacks - Added copyright notice; updated to PS Euclid interfaces.
26-Jun-85 10:56:01 - Jacks - Added d1 specific code.
23-Jul-85 13:59:03 - Jacks - Updated to Euclid Services interfaces, including XMessage; queuePages and fontPages added to GetPrintServiceActivity.
5-Aug-85 17:42:57 - Jacks - Updated some comments.
21-Aug-85 11:23:15 - Jacks - Moved Expunge to PSCommandInitImpl.
9-Sep-85 16:52:07 - Jacks - Use PSCommandExtras.ListDocumentsX.
24-Sep-85 14:10:09 - Jacks - Use PSCommand.ListDocuments again.
15-Oct-85 9:43:52 - Jacks - Converted to new banshee paper in PSState.
6-Nov-85 13:02:45 - Jacks - Get msg handle from PSKMessages.
21-Nov-85 11:24:07 - Jacks - Added ServiceState.