// P R I N T - DOVER // 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 IncBinSerial 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 Debug DebugSystem signalBand Func debugTrail knockResult numPrinted numMustPrint InitMeasure // Dover 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 BinSerials ] // internal statics static [ 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? simLateDisk // cStat ~~ Collect statistics on the appearance of Count-H (Dover only) // cStat ~~ Record minimum and maximum value of (nBands-current band) in // cStat ~~ count-H signal LAST appears during imaging of a page. // cStat ~~ Re-Initialize Sprint, or reset by hand, to reinitialize values cbMin = 32767 // cStat ~~ min value of (nBands-currentBand) cbMax = 0 // cStat ~~ max value -- nominal value is value of signalBand // delay ~~~~ debugging: delay per page to simulate printing debDelay = 0 // delay no delay std. // delay ~~~~ ] // File-wide structure and manifest declarations. manifest [ 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 ] // ROSCheck values structure CT: [ invert bit 1 // bit is on when things are good malFnReq bit 1 // Dover malfunction bit must also be on or no error failureCode bit 6 wordIndex bit 4 bitIndex bit 4 ] manifest // factors for creating table entries [ Invert = #100000 MalFnReq = #40000 Code = 256 Word = 16 Bit = 1 ] // ----------------------------------------------------------- // DoverPrint Initialization // ----------------------------------------------------------- // Returns -1 if printing is successfully completed, else // nPagesPrinted, so can pick up where we left off. let DrivePrinter(pDoc, nPagesAlreadyPrinted, lvFailureCode) = valof [ // ******** See SpruceMeasure -- don't move declarations of next five local variables ******** let malfunction, proceedCode, nonF, coldStart, consecutiveErrors = nil, nil, nil, nil, nil // ******** let CommTab=vec 10 CommTab=(CommTab+1)&(-2) // If monitoring dover performance, these are real InitializeHardware(false) InitMeasure(measureTable, 2000, (lv malfunction)-1) coldStart=true consecutiveErrors=0 let knockKnock = false // time to let somebody in if true // Print (cont.) Slow Loop // Loop out to here when a new font set is required, or when // needing to completely restart the printer. [Slow // Find out which page to print next: let copy = nil let page=PrintNext(pDoc, lv copy, nPagesPrinted) if page eq 0 then [ knockKnock = false; IncBinSerial(BinSerials+0); break ] if knockKnock then break // go let somebody in // Read in font and relocate the pointers to characters: let font=page>>PageG.fontLoad*(size FontG/16)+pDoc>>DocG.Fonts // Next call returns location of ICC table, let 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 buffers are. let nRecords= xmFonts? (pDoc>>DocG.ICCtotal+bandRecordSize-1) rshift logBandRecordSize, font>>FontG.nRecords let nfRecs=(nRecs-nRecords)/2 // max allowable band list size for normal alternation let LeftOver = LowAdr+(nRecords lshift logBandRecordSize) let LeftOverGuard = LeftOver+(loSize&(-4))-4 let buf1 = (LeftOver+loSize+8)&(-2) // ~~ all the 4's, 8's and 10's in here are cowardly slack let buf2=buf1+nfRecs lshift logBandRecordSize let curbuf=coldStart? buf2, buf1 // first real data imaged from buf1 // Now read in the bands for this page test coldStart then Zero(curbuf, nBands*2) or ReadBands(page, curbuf, nfRecs*2) // Initialize the Orbit, Dover, etc. InitializeHardware(false) let np = nil let tim = @RTC // Check for problems, wait for ready indication // wait for ready or some serious condition or for long enough unless Debug do [ np = ROSCheck(lvFailureCode, nPagesAlreadyPrinted, false) if np eq -1 break // ready if @lvFailureCode > maxNotReady % (@RTC-tim) > timeOut resultis np ] repeat // 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) // Now feed first sheet: DoFunc(fControl, 21b) // Turn off adCommandBeamOn, if on, revert to normal modulation // ~~ causes glitch AdCommand(AdapterScales) DoFunc(fROSCommand, adBufferReset) // If Dover is already running, this StartPrint may not do the right // thing, because it may be sent during the "dead" time near // CS-5. FeedASheet() AwaitPageSync(0) //Wait for sendVideo to go off. // Print (cont.) Fast Loop [RunningLoop // Calculate a ROS command table: CommTab!0=signalBand+2 CommTab!1=adExternalCommand1 //No feed yet CommTab!2=signalBand+1 CommTab!3=adExternalCommand1 CommTab!4=10000b+signalBand // last entry nearing obsolescence 3-26-78 DCS CommTab!5=32 *256 //Status bits 0-3 of word 8 CommTab!6=-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 // Prepare next page in parallel with imaging // Proceed code: // 0: Charge on ahead, full speed // 1: Pause because cannot fit bands or font for next page, // or because printing is done. // 2: Reprint this page, due to misfeed (Dover only). // 4: No sheet in pipe (Dover only) // Assume the page we are printing will be OK: unless coldStart then [ 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 then knockKnock = true // Find next page to work on: proceedCode=1 let nextbuf=curbuf xor buf1 xor buf2 let nextPage=PrintNext(pDoc,lv copy, nPagesPrinted) if (not knockKnock) & nextPage then [ if (nextPage>>PageG.fontLoad eq page>>PageG.fontLoad) & (nextPage>>PageG.nRecords le nfRecs) then [ proceedCode = 0 // Read in the bands for the next page: ReadBands(nextPage, nextbuf, coldStart? nfRecs*2, nfRecs) if simLateDisk then [ simLateDisk=simLateDisk xor 1 if (simLateDisk&1) eq 0 then Func!3=-1 ] DisableInterrupts() test Func!3 gr signalBand+3 then CommTab!1=adExternalCommand1+1 or proceedCode=4 EnableInterrupts() ] ] // Print (cont.) Wait for completion, analyze results // Now see if we actually printed this page properly. First, // wait for Orbit to announce it is finished. let imageTimeout = 4*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 nonF = 0 let stat=Func!9 //Orbit printing status. let countBand = Func!8 // Band in which count-H last occurred (Dover only) // ~~ cStat cbMin = Min(cbMin, countBand) //~~ cStat if countBand<nBands then cbMax = Max(cbMax, countBand) //~~ cSTat // ~~ cSTat // 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 // then check possible next page data enclobberment if ((proceedCode&1) eq 0) & nextbuf eq buf1 then proceedCode = 1 ] if nonF then @lvFailureCode = nonF if (stopsPrinting eq binFull) & (@lvFailureCode eq nonF) then @lvFailureCode = 130 AddToBin(500) // Now try for more specific engine status check np=ROSCheck(lvFailureCode, nPagesAlreadyPrinted, true) // Check COUNT-H signal, paper did not arrive -- else re-print page if coldStart eq 0 & // ~~ microcode checks explicitly at end of each band, as well as at signalBand (((CommTab!5)&1) eq 0 & countBand ge(nBands rshift 1))then proceedCode=proceedCode% (Func!3 le signalBand+3? 2, proceedCode eq 1? 0, 4) // Now wait for page sync to go off unless AwaitPageSync(0) then @lvFailureCode = 16 //Now decide what to do: if proceedCode then Announce(proceedCode) malfunction = @lvFailureCode if malfunction ge minDocumentError then malfunction = 0 // will not stop // First, if pipe is empty, fill it. Will not be invoked if pausing. if (proceedCode&4) ne 0 then [ AwaitPageSync(1) FeedASheet() AwaitPageSync(0) proceedCode=proceedCode-4 ] // Now react to the analysis: if at this point nothing is wrong and sheets are // feeding, steam ahead. Otherwise, return to the slow loop if data is not available // or if paper misfed. Return if there was a serious malfunction, or if things look // odd several times consecutively (paper failed to feed is the only case, for now) Measure(#23,(@(#123))+1) // force random event unless malfunction do [ if proceedCode eq 0 % proceedCode eq 2 & nonF ne 0 then [ coldStart=false curbuf=nextbuf consecutiveErrors=0 loop ] if proceedCode eq 1 then [ coldStart = false; break ] //Out of RunningLoop consecutiveErrors=consecutiveErrors+1 // misfeeds only, right now if consecutiveErrors ge 4 then [ malfunction, @lvFailureCode = 17, 17 np = nPagesPrinted ] ] Measure(#23,(@(#123))+1) // force random event if malfunction then [ InitializeHardware(true) // if malfunction detected outside of ROSCheck, set np let backup = 2 if np eq -1 then np = nPagesPrinted-backup // account for previous increment np = Max(np-1, nPagesAlreadyPrinted) CloseMeasure() // if measure code loaded, this is real, else dummy resultis np ] // If we get here, it is necessary to reprint this page. Paper is // probably flowing. Probably a paper misfeed // Exception: non-fatal malfunction (mf=0, but nonF isn't) -- give it up and go on unless nonF do nPagesPrinted=nPagesPrinted-1 if (proceedCode&1) ne 0 then break //Use pause code loop //Reprint the page, or go on ]RunningLoop repeat ]Slow repeat InitializeHardware(true) CloseMeasure() resultis (knockKnock % @lvFailureCode)? nPagesPrinted, -1 ] // -------------------------------------------------------------------------- // nPagesPrinted = ROSCheck(lvFailureCode, nPagesAlreadyPrinted, running,) // -------------------------------------------------------------------------- // 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 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: // [ // invert bit 1 // failureCode bit 7 // wordIndex bit 4 // bitIndex bit 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. // 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, running) = valof [ let ros8 = ROSStatus(8) let ros9 = ROSStatus(9) let localMode, scanning = nil, true // ready if not in local mode and if printer-specific tests indicate ready let ready = // Power on, no malfunction, paper tray OK, fuser warm (ros9࠴) eq #2000 & (ros8ߔ) eq 4 if ready then [ localMode = (ROSStatus(0)丠) ne 0 unless running do [ let lineCount = ROSStatus(7) & #170000 let rtc = ReadClock() until (ReadClock()-rtc) ge scanTicks loop scanning = (ROSStatus(7)𩠐) ne lineCount ] if localMode % not scanning then ready = false ] if ready % Debug resultis -1 // Analyze tables to identify the problem or condition preventing ready let tab = 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 + MalFnReq // 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 ] // 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 ] // Condition interpreter let code = 0 while @tab do [ let entry = @tab let isBit = (ROSStatus(entry<<CT.wordIndex) & bits!(entry<<CT.bitIndex)) ne 0? 1, 0 if isBit ne entry<<CT.invert & (entry<<CT.malFnReq eq 0 % (ros9d) ne 0) then [ code = entry<<CT.failureCode; break ] tab = tab + 1 ] // No other explicit problems, report local mode, or laser off, or unknown problem unless code do code = localMode? 11, scanning eq 0? 13, 7 @lvFailureCode = code let backup = code le maxManual? 0, code < 30? 2, 1 resultis Max(nPagesAlreadyPrinted, nPagesPrinted-backup) ] // ----------------------------------------- // Engine controls of various sorts. // ----------------------------------------- and FeedASheet() be [ Measure(#20,true) DoFunc(fROSCommand, adExternalCommand1+1) DoFunc(fROSCommand, adExternalCommand1) Measure(#20,false) ] // ----------------------------------------- // Hardware setup for various devices. // ----------------------------------------- and InitializeHardware(stop) be [ if Debug return InitRam(0) //Reset all RAM tasks, restart Trident if necessary DoFunc(fControl, 1) //Reset Orbit DoFunc(fROSCommand, adExternalCommand1) ] and Blast() be InitializeHardware(false) //BWBNovember 13, 1978 12:03 PM derived from SprucePrint // December 7, 1978 3:30 PM cleanup // 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 23, 1979 2:05 PM cleanup // January 28, 1981 12:40 PM don't swat if bad band entry probably due to leftover overflow // February 5, 1981 3:41 PM, add call on IncBinSerial