// P R I N T // errors 1000 // get "spruce.d" get "SpruceFiles.d" get "Orbit.d" // outgoing procedures external [ DrivePrinter ] // incoming procedures external [ SpruceError Max Min InitRam //SprucePrint AddToBin Announce AwaitPageSync PrintNext ReadBands ReadClock ReadFont //CURSOR CursorChar CursorDigit // SprucePrintRes DoFunc ROSStatus // Timer (debug only) SetTimer TimerHasExpired //OS Zero DisableInterrupts EnableInterrupts ] // incoming statics external [ scanTicks // # of 38 usec. ticks in 4 printer scan lines. logBandRecordSize bandRecordSize nPagesPrinted ros12 ros13 Debug DebugSystem Func debugTrail knockResult numPrinted numMustPrint Capabilities InitMeasure // engine control monitoring stuff CloseMeasure TickMeasure Measure measureTable xmFonts // Font data will be read into Bank 1 via Bank 0, if set nRecs LowAdr FAvalue nBands stopsPrinting ] // internal statics static [ revolution revsPerPage = 3 rosCount = 0 // Pimlico/puffin command count roscprob = 0 printSeq =10 // delay ~~~~ debugging: delay per page to simulate printing debDelay = 0 // delay no delay std. // delay ~~~~ ] // File-wide structure and manifest declarations. manifest [ sigband = 180 eTicks = 4 timeOut=15*27 printHysteresis = 15 // print this many before allowing suspension, each time in // ~~ above number may want to increase for large runs, or something? RTC=#430 debugTrailSize = 10*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 // printSeq values: warmup = 1 standby = 2 printing = 3 endofrun = 4 lowpaper = 5 badfeed = 6 badstrip =7 clearing = 8 malfClear = 9 ] // ----------------------------------------------------------- // Print Initialization // ----------------------------------------------------------- // Returns -1 if printing is successfully completed, else nPagesPrinted, so can pick up where we left off. let DrivePrinter(pDoc, nPagesAlreadyPrinted, lvFailureCode) = valof [ let measureVec = vec 5 let CommTab=vec 10 CommTab=(CommTab+1)&(-2) let knockKnock = false // time to let somebody in if true // We expect that at this time the printer's transports have been cleared from previous runs, and that we are // starting on a fresh sheet. Since there are three images for each sheet, revolution should be 0 nPagesPrinted = (nPagesPrinted/revsPerPage)*revsPerPage revolution=0 // the command to puffin to select color depends on revolution // the command to determine what to do with the paper depends on revolution let color = vec 5 let paperAction = vec 5 test revsPerPage eq 3 ifso [ color!0 = #63041 //magenta for first rev color!1 = #63021 //yellow for second rev color!2 = #63101 //cyan for third revolution color!3 = #63041 //magenta for first rev, next sheet color!4 = #63021 //yellow for second rev, next sheet paperAction!0 = #63203 //feed paper on rev 1 paperAction!1 = #63003 //noaction on rev 2 paperAction!2 = #63103 //strip paper on rev 3 paperAction!3 = #63203 //feed paper on rev 1, next sheet paperAction!4 = #63003 //noaction on rev 2, next sheet ] ifnot [ color!0 = #63041 //magenta for first rev color!1 = #63021 //yellow for second rev color!2 = #63101 //cyan for third revolution color!3 = #63201 //black for fourth revolution color!4 = #63041 //magenta for first rev, next sheet color!5 = #63021 //yellow for second rev, next sheet paperAction!0 = #63203 //feed paper on rev 1 paperAction!1 = #63003 //noaction on rev 2 paperAction!2 = #63003 //noaction on rev 3 paperAction!3 = #63103 //strip paper on rev 4 paperAction!4 = #63203 //feed on rev 1, next sheet paperAction!5 = #63003 //noaction on rev 2, next sheet ] // During the run we need to track the location of sheets we have already printed. Bits 13, 14 and 15 of xportModel <on> // represent sheets in transports C, B and A, respectively. xportModel is shifted left after every revolution; // '1' is or'd onto it after revolutions where paperAction was 'strip'. let xportModel = 0 InitializeHardware(true) InitMeasure(measureTable, 2000, measureVec) ROSCommand(#63010, lv roscprob) // reset remote printing queue roscprob = roscprob&3 //don't care if these commands ignored if roscprob then [ @lvFailureCode = roscprob+77; CloseMeasure(); resultis nPagesPrinted ] let needFonts, startRun, needInit =true, true, true let nC, copy, FontTable, nfRecs, LeftOver, LeftOverGuard = nil, nil, nil, nil, nil, nil let curbuf, buf1 = nil, nil let np, tim = nil, nil let nextPage=PrintNext(pDoc, lv copy, nPagesPrinted) let nextNext=PrintNext(pDoc, lv nC, nPagesPrinted+1) // Print (cont.) [PrintLoop // Find out which page to print next: let page=nextPage if page eq 0 then [ knockKnock = false; break ] if knockKnock then break // go let somebody in if stopsPrinting eq binFull do [ @lvFailureCode = 130; break] // Read in font and relocate the pointers to characters: if needFonts do [ let font=page>>PageG.fontLoad*(size FontG/16)+pDoc>>DocG.Fonts // Next call returns location of ICC table, FontTable = ReadFont(font, LowAdr, nRecs) unless xmFonts do for i=0 to pDoc>>DocG.ICCtotal-1 do // if rasters are in bank 1, they start at 0 FontTable!i=FontTable!i + LowAdr FontTable=FontTable-100000b // Figure out where the buffer is. let nRecords= xmFonts? (pDoc>>DocG.ICCtotal+bandRecordSize-1) rshift logBandRecordSize, font>>FontG.nRecords nfRecs=(nRecs-nRecords) LeftOver=LowAdr+(nRecords lshift logBandRecordSize) LeftOverGuard = LeftOver+(loSize&(-4))-4 curbuf = (LeftOver+loSize+8)&(-2) // ~~ all the 4's, 8's and 10's in here are cowardly slack needFonts = false ] // Now read in the bands for this page ReadBands(page, curbuf, nfRecs) if needInit do [ // Initialize the Orbit, etc. InitializeHardware(false) let np = nil let tim = @RTC // wait for ready or some serious condition or for long enough unless Debug do [ np = ROSCheck(lvFailureCode, nPagesAlreadyPrinted, standby, lv xportModel) if np eq -1 break // ready if np ge 0 resultis np //result was -2: not ready yet, but may be soon. Have we waited long enough? if (@RTC - tim) > timeOut do [ @lvFailureCode = 5; CloseMeasure(); resultis nPagesPrinted] ] repeat // establish queue entries: a null entry and the first two real entries ROSCommand(#63020, lv roscprob) // for null revolution ROSCommand(#63020, lv roscprob) // append new queue entry ROSCommand(#63204, lv roscprob) //lightsource = video ROSCommand(color!revolution, lv roscprob) //select toner to use this rev ROSCommand(paperAction!revolution, lv roscprob) //feed, strip or nothing ROSCommand(#63020, lv roscprob) // append new queue entry ROSCommand(#63204, lv roscprob) //lightsource = video ROSCommand(color!(revolution+1), lv roscprob) //select toner to use next rev ROSCommand(paperAction!(revolution+1), lv roscprob) //feed, strip or nothing ROSCommand(#63006, lv roscprob) // start engine if roscprob do [@lvFailureCode = roscprob+74; break] // Try to empty Orbit buffers to clear them. This is to minimize toner dumping on first (blank) page. compileif loSize ls 256 then [ foo=nil ] for i=0 to 31 do DoFunc(fReadBlock, 256, LeftOver) AwaitPageSync(0) //Wait for sendVideo to go off. needInit = false ] // Print (cont.) //now set up to build the next entry while bands for this image are going out - action disabled for now. CommTab!0=-1 CommTab!1=#63020 //append new queue entry CommTab!2=sigband - 10 // will be set to 3 when we're ready CommTab!3=#63204 //lightsource ← setvideo CommTab!4=sigband - 20 CommTab!5=color!(revolution+2) CommTab!6=sigband - 30 CommTab!7=paperAction!(revolution+2) CommTab!8=-1 // Start Orbit working on the present page. DoFunc(fControl, #21) //Reset, clear behind DoFunc(fROSCommand, adBufferReset) LeftOver!0=0 //Initialize LeftOver table LeftOverGuard!1=-1 tim=@RTC // Start the microcode!!!! DoFunc(fSlot, CommTab, 20000, nBands-1, FAvalue, LeftOver, FontTable, curbuf-1, nil, nil, (copy lshift 5)+4) if Debug then // ~~delay [ // ~~delay while (@RTC-tim) < debDelay loop // ~~delay tim = @RTC // ~~delay don't invoke timeout code below ] // ~~delay // Assume the page we are printing will be OK: nPagesPrinted=nPagesPrinted+1 CursorDigit(nPagesPrinted) // See who's (maybe) knocking at my door // This logic is copied from SpruceUtilsRes: if we are not planning to defer to spooler, // don't trouble to shut down here, just to find that out there. Would be too expensive if (DebugSystem) eq 0 & numPrinted ge numMustPrint & knockResult & (nPagesPrinted-nPagesAlreadyPrinted) > printHysteresis & revolution eq revsPerPage //stripping -- to prevent clearing a partially printed sheet then knockKnock = true nextPage, copy = nextNext, nC nextNext = PrintNext(pDoc, lv nC, nPagesPrinted+1) if (not knockKnock) & nextNext then //Unless this page gets messed up we will continue printing. //We want to be sure that puffin's queue won't empty. Tell orbit to send out the 'append q entry' now. [ CommTab!0 = sigband //enable interband ROS command rosCount = rosCount + 4 //and keep in sync if (nextPage>>PageG.fontLoad ne page>>PageG.fontLoad) then needFonts = true ] // Print (cont.) Now see if we actually printed this page properly. // First, wait for Orbit to announce it is finished. let imageTimeout = 15*27 while @#720 ne 0 do if (@RTC-tim) gr imageTimeout then [ Blast() // clear hardware, #720 // Machine dead or Orbit got behind and it wasn't detected // Will generally be overriden by more specific analysis @lvFailureCode = 19 // Manual intervention required break ] // Check Orbit status let nonF = 0 let stat=Func!9 //Orbit printing status. // Fatal error detected by microcode -- invalid Band entry -- possibly broken processor if stat<<STATUS.invalidBandEntry then [ InitializeHardware(true); if LeftOverGuard!1 eq -1 then SpruceError(1010, @1, @2) //else, assume that //bad band entry is simply result of leftover overflow ] test stat<<STATUS.prematurePageAbort then [ Announce(16); nonF = 301 ] or if stat<<STATUS.behind then [ Announce(16); nonF = 300 ] if stat<<STATUS.timeout then [ Announce(17); @lvFailureCode = 18 ] if LeftOverGuard!1 ne -1 then [ Announce(18); nonF = 310 ] if nonF then @lvFailureCode = nonF // Now try for more specific engine status check let running = printing if nextPage eq 0 do running = endofrun np=ROSCheck(lvFailureCode, nPagesAlreadyPrinted, running, lv xportModel) // Now wait for page sync to go off unless AwaitPageSync(0) then @lvFailureCode = 16 //Now decide what to do: let malfunction = @lvFailureCode if malfunction ge minDocumentError then malfunction = 0 // will not stop if revolution eq 3 then AddToBin(50) //if stripping, add to count of sheets out // Now react to the analysis: if at this point nothing is wrong and sheets are feeding, steam ahead. test malfunction ifnot [ //adjust model of Puffin's transport system xportModel = (xportModel lshift 1)+(revolution eq (revsPerPage-1)?1,0) revolution = (revolution+1) rem revsPerPage //puffin drum revolution ] ifso [ InitializeHardware(true) let backup = nPagesPrinted-1 rem revsPerPage // if malfunction detected outside of ROSCheck, set np if malfunction eq 3 % malfunction eq 9 % malfunction eq 1 do [ test nextPage ifnot [ CloseMeasure(); resultis -1 ] //no more to do ifso [ nPagesPrinted = nPagesPrinted - backup break //Out of RunningLoop ] ] if np eq -1 then np = nPagesPrinted-backup // account for previous increment nPagesPrinted = Max(np-1, nPagesAlreadyPrinted) break ] ]PrintLoop repeat InitializeHardware(true) CloseMeasure() resultis (knockKnock % @lvFailureCode)? nPagesPrinted, -1 ] // -------------------------------------------------------------------------- // nPagesPrinted = ROSCheck(lvFailureCode, nPagesAlreadyPrinted, running, // lvXportModel) added for puffin // -------------------------------------------------------------------------- // 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. // A check, designed chiefly for Dover, verifies that the laser is on and the polygon is // scanning (SOS/EOS are seeing things), by making sure that the low four bits of the line // count (indicated in status word) are changing. The code reads the line count, waits // approximately the time needed for four scan lines (generous margin), then reads the // count again, reporting a problem if the values are equal. This test happens only when // the running parameter is false. The wait time (scanTicks) is computed in PrintInit, as: // ResolutionS is scaled by 10 as stored, PaperSpeedInches by 100. The (fast 10 bits of) // the RTC ticks at 38 usec. intervals. Thus the # ticks wanted for four lines is: // ( 4 lines x 10↑6 usec/sec x 1/38 tick/usec.) / ((PaperSpeedInches/100 x ResolutionS/10) lines/sec) // or about (106 x 10↑3) / (PaperSpeedInches/100 x ResolutionS/10) ticks -- about 30 for Dover. // This is only approximate because ROSStatus time, about 10 ticks for Dover, is not included. // Part of the reason for waiting four line times is to account for possible delays in obtaining // the correct line count status. Later, this method can be used to check for correct polygon speed. // The scanTicks static is shifted left by 6 to match the clock reading function's results // ROSCheck (cont) and ROSCheck(lvFailureCode, nPagesAlreadyPrinted, expected, lvXportModel) = valof [ ros12 = ROSStatus(12) ros13 = ROSStatus(13) let scanning = true let mode, mainSeq, subSeq, malFnStatus = nil, nil, nil, nil malFnStatus, subSeq, mainSeq, mode = ros13Ź, (ros13 rshift 8)&7, (ros13 rshift 11)&7, ros13 rshift 14 switchon mainSeq into [ case 1: case 2: printSeq = warmup; endcase // poweron, warmup case 3: printSeq =standby; endcase // case 4: switchon subSeq into [ case 0: printSeq = printing; endcase // case 1: printSeq = endofrun; endcase // case 2: printSeq = lowpaper; endcase case 3: printSeq = badfeed; endcase case 4: printSeq = badstrip; endcase case 5: printSeq = clearing; endcase default: printSeq = 86 // subSeq error ]; endcase case 5: printSeq = malfClear; endcase // default: printSeq = 88 //Mainseq error ] // ready if not in local mode and if printer-specific tests indicate ready let ready = (printSeq eq expected) & // puffin is where we think it should be malFnStatus eq 0 & (ros12 & #17377) eq rosCount & //no malf and no queue problems mode eq 1 // and puffin is in remote print mode if ready & (printSeq ne printing) then [ let lineCount = ROSStatus(7) & #170000 let rtc = ReadClock() until (ReadClock()-rtc) ge scanTicks loop scanning = (ROSStatus(7)𩠐) ne lineCount ] if ready & scanning % Debug resultis -1 // Analyze tables to identify the problem or condition preventing ready let tab = table [ // error code,, machine code 10 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 ] // Condition interpreter let x = EngineCommErr(ros12) if x ne 0 do [ x = x+71 ] let code = 0 test mode ne 1 then code = 11 //~~~~~~~~~~~~~~~~~~ or test ros12 < 0 then code = 50 or test malFnStatus eq 0 then code = printSeq > malfClear? printSeq, x or test #200 le malFnStatus & malFnStatus le #240 then code = 64 // 80-A0 T events missed or while @tab do [ let entry = @tab if malFnStatus eq (entryŹ) then [ code = entry rshift 8; break ] tab = tab + 1 ] // ROSCheck (cont) // 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. // No other explicit problems, report local mode, or laser off, or unknown problem unless code do [ test scanning ifnot code = 1 ifso [ if printSeq ne expected resultis -2 code =7 ] ] @lvFailureCode = code let revsPerPage = 3 + (Capabilities &mBlackHousing)?1,0 let backup = nPagesPrinted rem revsPerPage // reprint sheet on drum if any switchon code into [ case 58 to 65: case 52 to 54: //reprint sheet at C transport if any if @lvXportModel & 4 ne 0 do backup = backup + revsPerPage case 57: //reprint sheet at B transport if any if @lvXportModel & 2 ne 0 do backup = backup + revsPerPage case 55: //reprint sheet at A transport if any if @lvXportModel & 1 ne 0 do backup = backup + revsPerPage case 2: case 7: case 8: case 11 to 51: if nPagesPrinted rem revsPerPage eq 0 do //reprint sheet we think we should have stripped from drum backup = backup + revsPerPage ] @lvXportModel = 0 resultis Max(nPagesAlreadyPrinted, nPagesPrinted-backup) ] // ----------------------------------------- // Hardware setup for various devices. // ----------------------------------------- and InitializeHardware(resetEngineSeq) be [ if Debug return InitRam(0) //Reset all RAM tasks, restart Trident if necessary DoFunc(fControl, 1) //Reset Orbit if resetEngineSeq do [ ROSCommand(#60000, lv roscprob) // Reset command count if roscprob eq 0 do [ ROSCommand(#63050, lv roscprob) // Read out malfunction data, clear malf. roscprob = roscprob & 3 ] ] ] and Blast() be InitializeHardware(false) and ROSCommand(x, lvError; numargs na) be [ test x eq #60000 ifso roscprob, rosCount = 0, 0 ifnot rosCount = rosCount + 1 DoFunc(fROSCommand, x) unless (na ne 2) % Debug do [ let tim, good = @RTC, false until (@RTC - tim) ge eTicks do [ ros12 = ROSStatus(12) if (rosCount & #377) eq (ros12 & #17377) then [ good = true; break ] ] if not good then @lvError = EngineCommErr(ros12) ] ] and let EngineCommErr(x) = valof [ if (x & #10000) eq #10000 do [ if (x & #4000) eq #4000 resultis 3 if (x & #2000) eq #2000 resultis 2 if (x & #1000) eq #1000 resultis 3 resultis 4 ] if (x& #377) ne (rosCount & #377) resultis 1 resultis 0 ] //BWB. November 13, 1978 12:36 PM derived from spruceprint // December 11, 1978 reset remote queue doesn't append q entry anymore. Polishit up some. // January 2, 1979 3:41 PM modify ROSCheck to preserve status // February 23, 1979 4:09 PM cleanup // March 7, 1979 2:11 PM add 4-color capability // April 27, 1979 11:45 AM, add Dover Engine Control Monitoring code, see SpruceMeasure, by Swinehart // add ability to place fonts in bank 1 -- see all uses of xmFonts // repair bug in BankBlt interface for xmFonts stuff // May 17, 1979 4:43 PM repair errors // May 23, 1979 3:08 PM, fix measure interface // August 1, 1979 3:14 PM, mBlack became mBlackHousing ??!! // February 2, 1981 4:30 PM, don't swat if bad band entry probably due to leftover overflow