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: BOOLEAN ← FALSE;
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:
BOOLEAN ←
NOT 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;
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
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.
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.
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.
26-Jun-85 10:56:01 - Jacks - Added d1 specific code.
24-Sep-85 14:10:09 - Jacks - Use PSCommand.ListDocuments again.
21-Nov-85 11:24:07 - Jacks - Added ServiceState.