// P R I N T O R B I T H D W F N S
// errors 1000
//

get "PressInternals.df"
get "PressParams.df"
get "Orbit.D"

// outgoing procedures
external
[
AddQEntry;AdCommand;IFunc;ROSCheck
FeedASheet;InitializeHardware;ROSCommand;ROSStatus;ReadAdapterStatus
JogReady
]

// incoming procedures
external
[
PressError
Max;DoFunc

//CURSOR
CursorChar
CursorDigit
CursorToggle

//OS
Zero
MoveBlock
StartIO
CallSwat
DisableInterrupts
EnableInterrupts

//PRESSML
Ugt
DoubleCop
//PRESS
DblShift

//WINDOWS,FILE
FileReadPage
FileVDA
WindowInit
WindowSetPosition
WindowReadBlock

]

// incoming statics
external
[
BitsFile
sysDisk

BandFile
printerDevice
printerForward
Debug
breakPage
pFonts
ICCtot

//PRINTORBITINIT
nVisibleBands
nLeadingBands
nTrailingBands
FA
maxPrintPassRecs
BitScale
MotorScale
BitClock
MotorSpeed
LineSyncDelay
PageSyncDelay
VideoGate
Tadapter

nPrinterColors
]

//internal statics
static
[
rosCount = 0//P,Pimlico command count
rosSyncError = false // Pimlico -- sync problem
jogT1 = 10*27
jogT2 = 6*27
]

// File-wide structure and manifest declarations.

manifest [
RTC=#430
loSize=1200//Enough for 300 left-over characters or lines
debugTrailSize=20*3

// Failure Code ranges -- see ROSCheck
maxNotReady = 9 // not ready, but probably will be soon
maxManual = 19 // Manual intervention required
maxJam = 99// Error during operation
minDocumentError = 300 // Document inherently hard to print
]

// ROSCheck values
structure CT:
[
invertbit 1
failureCodebit 7
wordIndexbit 4
bitIndexbit 4
]

manifest // factors for creating table entries
[
Invert= #100000
Code= 256
Word= 16
Bit= 1
]

manifest
[
//P commands
PResetRemoteQueue=#63010
PStartRemoteQueue=#63006
PStart3ColorVideo=#63346
PStart3ColorScan=#63246
PStart4ColorVideo=#63306
PStart4ColorScan=#63206
PAppendQueueEntry=#63020
PSetVideo=#63204
PNoPaperAction=#63003
PFeedPaper=#63203
PReleasePaper=#63103
PSinglePass=#63303
PNoColor=#63001
PSetColor6=#63201//usually black
PSetColor7=#63101//usually cyan
PSetColor9=#63041//usually magenta
PSetColor11=#63021//usually yellow
//P printSeq states
Pwarmup=1
Pstandby=2
Pprinting=3
Pendofrun=4
Plowpaper=5
Pbadfeed=6
Pbadstrip=7
Pclearing=8
PmalfClear=9
]

let AddQEntry(color,paperAction) be
[
ROSCommand(PAppendQueueEntry)
ROSCommand(PSetVideo)
ROSCommand(color)
ROSCommand(paperAction)
]

and AdCommand(x) be IFunc(fROSCommand, x)

and IFunc(f, x) be
[
if Debug then return
let tab=vec 10
tab=(tab+1)&(-2)
tab!0=f
tab!1=x
// Get microcode to see command:
@#720=tab
StartIO(#4)
// Wait for microcode to complete
while @#720 ne 0 do loop
]

// -----------------------------------------------------------------
// nPagesPrinted = ROSCheck(lvFailureCode, nPagesAlreadyPrinted, running, nPagesPrinted)
// ------------------------------------------------------------------

// analyze ROS status
// nPagesPrinted = -1 if there are no malfunctions, ROS is ready to print
//
otherwise, the number of pages to report as having been printed
// @lvFailureCode will contain an analysis of the current state. The code values are
//
described below.
// nPagesAlreadyPrinted places a lower bound on the nPagesPrinted result. This
//
prevents loops through this code from backing up too far.
// running
true if caller thinks main drive is allowed to be on for "ready"
//
result, false otherwise (waiting for ready).

// ROSCheck first screens the current status for any malfunction indications, and
// returns right away if there are none. Otherwise, it applies the current status
// against a printer-dependent table of possible conditions, yielding a failure
// code and a new page value -- the last page certain to have been reliably
// printed. One possible condition is "no malfunction detected", which will only
// be issued for printers that give no positive indication when they are merely
// busy doing normal things.
// N.B. @lvFailureCode is not changed when no conditions are found

// The failure codes divide into ranges:
// 0-9
Not ready, but no indication of problems or will clear up automatically
//
(includes fuser cold, warmup mode, clearing revolutions, etc.)
// 10-19
Manual intervention required before machine can become ready
//
(paper low, power not there, etc.)
// 20-99
Jams and other operational malfunctions (many codes provided so that
//
each device can report machine-dependent jam explanations)
// 100-200
Inherent problems (e.g., insufficient bandwidth somewhere) that are
//
not curable by mere mortals. Attempts to improve the situation should be
//
abandoned.
// 200-300
Inherent problems encountered, but they did not terminate printing. One
//
should expect that one or more pages were improperly imaged.

// The machine-dependent control table is constructed using this pattern:

// structure CT:
//
[
//
invertbit 1
//
failureCodebit 7
//
wordIndexbit 4
//
bitIndexbit 4
//
]

// invert means that the bit is on when the condition is not a problem (e.g., "Ready")
// failureCode should be reported when the condition specified by the bitIndex’th
//
bit inROS status word wordIndex is a problem.
// (Pimlico uses a different format: right byte is status code returned from machine,
//
left byte is status code returned from ROSCheck

// ROSCheck (cont)

and ROSCheck(lvFailureCode, nPagesAlreadyPrinted, running, nPagesPrinted) = valof
[

let ros8 = ROSStatus(8)
let ros9 = ROSStatus(9)
let ros12 = ROSStatus(12)
let ros13 = ROSStatus(13)
let malFnStatus=ros13Ź
let seqStatus = ros13 rshift 8

let ready = selecton printerDevice into
[
// Power on, no malfunction, paper tray OK, fuser warm
case printerDover: (ros9࠴) eq #2000 & (ros8ߔ) eq 4
// Ready, no malfunction or no malfunction (depends on running)
case printerSequoia: (ros9&(running? #100, #300)) eq 0
// Ready or no malfunction (depends on running)
case printerPimlicoAlt: (ros9&1) ne 0 % (running& ((ros9Ś) eq 2))
// Standby or no malfunction (depends on running)
case printerPimlico: ros12 ge 0 & malFnStatus eq 0 // &
// (seqStatus eq 3 % // 3=standby, 4=printing, 9=clearing
// (running & (seqStatus eq 4 % seqStatus eq 9)))
case printerPuffin: valof
[let subSeq=seqStatus&7
let mainSeq = (seqStatus rshift 3)&7
let mode = seqStatus rshift 6
let printSeq=selecton mainSeq into
[case 1: case 2: Pwarmup
case 3: Pstandby
case 4: selecton subSeq into
[ case 0: Pprinting
case 1: Pendofrun
case 2: Plowpaper
case 3: Pbadfeed
case 4: Pbadstrip
case 5: Pclearing
default: 86
]
case 5: PmalfClear
default: 88
]
//if running, expect Pstandby
//else, either Pprinting or Pendofrun
let expected=running?
((printSeq eq Pendofrun)%(printSeq eq Pprinting)),
(printSeq eq Pstandby)
let rdy=expected&//Puffin in right place
(malFnStatus eq 0)&//no malfunction
((ros12䏡) eq rosCount)&//no queue problems
(mode eq 1)//remote print mode
unless rdy do resultis false
if printSeq ne Pstandby then resultis true
//we’re ready, and in standby: check for scanning
let lineCount = ROSStatus(7)𩠐
let rtc=@RTC
let scanTicks=32//# of ticks in 4 scans
until (@RTC-rtc) ge scanTicks do [ ]
resultis (ROSStatus(7)𩠐) ne lineCount
]
default: true
]

if ready % Debug resultis -1

// Analyze tables to identify the problem or condition preventing ready

let tab = selecton printerDevice into
[
case printerDover: table [
10*Code + 8*Word + 5*Bit // PTDisorder-H Check paper tray
20*Code + 8*Word + 10*Bit // 27LS-H Jam -- paper feed
21*Code + 8*Word + 14*Bit // LostPower-H Lost engine power
22*Code + 9*Word + 1*Bit // PhotoCellOut-H Jam--paper on drum
23*Code + 9*Word + 2*Bit // PreSeq-H Jam -- startup sequence
24*Code + 9*Word + 6*Bit // 38LS-H Jam--paper on fuser roll
25*Code + 9*Word + 10*Bit // 3LS-H Jam--paper on drum
14*Code + 8*Word + 13*Bit + Invert // ReadyTemp-H Fuser not warm
12*Code + 9*Word + 5*Bit + Invert // ACMonitor-H Engine not powered up
26*Code + 9*Word + 9*Bit // Malfunction-H unexplained malfunction
0 ]
case printerSequoia: table [
4*Code + 8*Word + 13*Bit // Fuser not warm
11*Code + 8*Word + 5*Bit // Check paper tray
30*Code + 9*Word + 2*Bit // Jam
31*Code + 9*Word + 9*Bit // Unexplained Malfunction
1*Code + 9*Word + 8*Bit // Not ready
0 ]
case printerPimlicoAlt: table [
40*Code + 9*Word + 9*Bit // Service Call
41*Code + 9*Word + 8*Bit // Call Key Operator
13*Code + 9*Word + 10*Bit // Check Paper Tray
5*Code + 9*Word + 13*Bit // Warming up or otherwise not ready
6*Code + 9*Word + 14*Bit // Wait For Copy -- not ready
0 ]
case printerPuffin:
case printerPimlico: table [ // error code,, machine code
15 lshift 8 + #32 // 1A 2/2 low paper.
52 lshift 8 + #00 // 00 X missed.
53 lshift 8 + #04 // 04 malfunction memory set.
54 lshift 8 + #10 // 08 1/1 FIRE!!!!!!!!
55 lshift 8 + #16 // 0E 1/4 Transport A.
56 lshift 8 + #34 // 1C 2/3 Paper grip.
57 lshift 8 + #36 // 1E 2/4 Transport B.
58 lshift 8 + #50 // 28 3/1 Fuser interlock open.
59 lshift 8 + #54 // 2C 3/3 Bottom tray interlock open.
60 lshift 8 + #56 // 2E 3/4 Transport C jam.
61 lshift 8 + #74 // 3C 4/3 Front door open.
62 lshift 8 + #116// 4E 5/4 Toner call.
63 lshift 8 + #150// 68 7/1 Functional interlock open.
0 ]
default: table [ 0 ]
// Codes generated elsewhere:
//
7 -- no specific malfunction detected, but something is wrong
//
16 -- page sync never turned off
//
17 -- several consecutive unidentified errors
//
18 -- Orbit timed out -- page sync never arrived, or engine died or got behind
//
19 -- Alto code timed out -- same symptoms
//
300 -- Orbit got behind, but page terminated normally
//
301 -- Orbit got behind, had to quit early
//
310 -- Left over table got too large. Please report to fixer.
]

let bits = table [ #100000;
#40000; #20000; #10000
#4000; #2000; #1000
#400; #200; #100
#40; #20; #10
#4; #2; #1]

// ROSCheck (cont)

// Condition interpreter

let code = 0
if printerDevice eq printerPimlico then
test rosSyncError then code = 51
or test ROSStatus(12) < 0 then code = 50
or test malFnStatus eq 0 then code = selecton seqStatus into
[ case 1: case 2: 2; case 9: case 10: 3; case 4: 8; case 5 to 8: 9; default: 0 ]
or if #200 le malFnStatus & malFnStatus le #240 then code = 64 // 80-A0 T events missed
unless code while @tab do
[
let entry = @tab
test printerDevice eq printerPimlico
ifnot if ( ( ROSStatus(entry<<CT.wordIndex) & (bits!(entry<<CT.bitIndex)) )
xor entry<<CT.invert ) ne 0 then
[ code = entry<<CT.failureCode; break ]
ifso if malFnStatus eq (entryŹ) then [ code = entry rshift 8; break ]
tab = tab+1
]
// Perhaps this condition ought to be promoted to a higher value
unless code do code = 7
// No specific malfunction found -- what’s happening?
@lvFailureCode = code
// 0 if no jam, 2 for Dover, else 1
let backup = code le maxManual? 0, code < 30? 2, 1
resultis Max(nPagesAlreadyPrinted, nPagesPrinted-backup)
]

and FeedASheet() be switchon printerDevice into
[
case printerDover:
ROSCommand(adExternalCommand1+1)
ROSCommand(adExternalCommand1)
endcase
case printerDurango:
ROSCommand(61400b)
endcase
case printerSequoia:
ROSCommand(60000b)
ROSCommand(60001b)
endcase
case printerPimlicoAlt:
ROSCommand(#64001)// Push "print" button, lamp inhibit
// Code in main loop will let go of it.
endcase
case printerPimlico:
ROSCommand(#63346)// Start, using std. 3 color video queue
endcase
case printerPuffin:
endcase//sheet feeding already in paperaction queue
]

// -----------------------------------------
// Hardware setup for various devices.
// -----------------------------------------

and InitializeHardware(stop) be
[
if Debug return
//done by Overlay:
StartIO(100000b)//Get out of RAM
//done by Overlay:
SetRMR(177774b)//Start emulator, task 1 in RAM (rmr = blv)
//done by Overlay:
StartIO(100000b)//Back into RAM
//done by Overlay:
SetRMR(177776b)//To silent boot next time

DoFunc(fControl, 1)//Reset Orbit

switchon printerDevice into
[
case printerPuffin:
if stop then
[ROSCommand(#60000)//reset command count
ROSCommand(#63050)//read out malfunction data, clear malf
]
endcase
case printerDover: ROSCommand(adExternalCommand1); endcase

case printerDurango:
[
let t=@RTC
while @RTC-t ls 27*2 do loop
test stop then ROSCommand(#77660)//Close shutter
or ROSCommand(#77760)//Open shutter
] ; endcase
case printerPimlicoAlt:
if stop then [
let t=@RTC
ROSCommand(#60005)// Press "stop print", for luck.
while (@RTC-t) ls 27/4 loop// Wait 250 ms.
]
ROSCommand(#60000)// Release all buttons, incl. lamp inhibit
endcase
case printerPimlico:
rosCount, rosSyncError = 0, false
ROSCommand(#60000, false)// Reset command count
ROSCommand(#63050)// Read out malfunction data, clear malf.
// ROSCommand(#63217)// SetPageSyncEvent to 25
if stop then ROSCommand(#63040)// Stop now.
endcase
]
]

and ROSCommand(x, sync; numargs na) be
switchon printerDevice into
[ case printerPuffin: na=2;sync=1;//endcase intentionally omitted
case printerPimlico:
[if na<2 then sync = 4
test x eq #60000 then rosCount=0
or if printerDevice eq printerPuffin then rosCount=rosCount+1
let good = true
for i = 1 to sync? sync, 1 do
[DoFunc(fROSCommand, x)
unless sync break
let tim = @RTC; good = false
while (@RTC-tim) le 25 do
if (rosCountŹ) eq (ROSStatus(12)Ź) then
[ good = true; break
]
if good break
ROSCommand(#60000, false)
rosCount, rosSyncError = 0, false
]
unless good do rosSyncError = true
unless printerDevice eq printerPuffin do rosCount = rosCount+1
endcase
]
default:DoFunc(fROSCommand, x)
]

and ROSStatus(w) be DoFunc(fROSStatus, w*(4*256))

and ReadAdapterStatus(v) be
for i=0 to 11 do v!i=ROSStatus(i)

// PimlicoAlt only -- timed out -- just push button and continue if coming ready
and JogReady() = valof
[
let sink = nil
let tim = @RTC
// timeout is careully set to > 1 rev, < 2. If ready doesn’t come on in another timeout
// something’s broke, give up
while ROSCheck(lv sink, 0, false) ne -1 do if (@RTC-tim)>jogT1 resultis false
FeedASheet()// Push Start Print
tim = @RTC
while (@RTC-tim)<3 loop// Wait for relay to latch
ROSCommand(#60001)// Release button
tim = @RTC
while (@RTC-tim)<jogT2 loop // Carefully chosen interval before continuing
resultis true
]